/**
 * 
 */
package io.finer.erp.jeecg.stock.service.impl;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.api.client.util.Maps;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import io.finer.erp.jeecg.bas.entity.BasCustomer;
import io.finer.erp.jeecg.bas.entity.BasMaterial;
import io.finer.erp.jeecg.bas.entity.BasMaterialCategory;
import io.finer.erp.jeecg.bas.entity.BasMaterialTemp;
import io.finer.erp.jeecg.bas.entity.BasMeasureUnit;
import io.finer.erp.jeecg.bas.entity.BasPfMaterial;
import io.finer.erp.jeecg.bas.entity.BasProductFormula;
import io.finer.erp.jeecg.bas.entity.BasSupplier;
import io.finer.erp.jeecg.bas.entity.BasWarehouse;
import io.finer.erp.jeecg.bas.entity.ZrkDeliver;
import io.finer.erp.jeecg.bas.entity.ZrkDeliverEntry;
import io.finer.erp.jeecg.bas.entity.ZrkOrderProcess;
import io.finer.erp.jeecg.bas.entity.ZrkOrderProduct;
import io.finer.erp.jeecg.bas.entity.ZrkQzOrder;
import io.finer.erp.jeecg.bas.entity.ZrkShoporder;
import io.finer.erp.jeecg.bas.entity.ZzDeviceType;
import io.finer.erp.jeecg.bas.mapper.BasMaterialCategoryMapper;
import io.finer.erp.jeecg.bas.service.IBasCustomerService;
import io.finer.erp.jeecg.bas.service.IBasMaterialCategoryService;
import io.finer.erp.jeecg.bas.service.IBasMaterialService;
import io.finer.erp.jeecg.bas.service.IBasMaterialTempService;
import io.finer.erp.jeecg.bas.service.IBasMeasureUnitService;
import io.finer.erp.jeecg.bas.service.IBasPfMaterialService;
import io.finer.erp.jeecg.bas.service.IBasProductFormulaService;
import io.finer.erp.jeecg.bas.service.IBasSupplierService;
import io.finer.erp.jeecg.bas.service.IBasWarehouseService;
import io.finer.erp.jeecg.bas.service.IZrkDeliverService;
import io.finer.erp.jeecg.bas.service.IZrkOrderProcessService;
import io.finer.erp.jeecg.bas.service.IZrkOrderProductService;
import io.finer.erp.jeecg.bas.service.IZrkQzOrderService;
import io.finer.erp.jeecg.bas.service.IZrkShoporderService;
import io.finer.erp.jeecg.bas.service.IZzDeviceTypeService;
import io.finer.erp.jeecg.finance.service.IFinaPaymentService;
import io.finer.erp.jeecg.stock.entity.StkCheckBill;
import io.finer.erp.jeecg.stock.entity.StkCheckBillEntry;
import io.finer.erp.jeecg.stock.entity.StkInventory;
import io.finer.erp.jeecg.stock.entity.StkIoBill;
import io.finer.erp.jeecg.stock.entity.StkIoBillEntry;
import io.finer.erp.jeecg.stock.entity.StkIoMaterialLog;
import io.finer.erp.jeecg.stock.entity.StkPickUpBill;
import io.finer.erp.jeecg.stock.entity.StkPickUpEntry;
import io.finer.erp.jeecg.stock.entity.StkTray;
import io.finer.erp.jeecg.stock.entity.StkTrayDetail;
import io.finer.erp.jeecg.stock.entity.ZrkOrderProductMaterialLk;
import io.finer.erp.jeecg.stock.mapper.ScanMapper;
import io.finer.erp.jeecg.stock.mapper.StkIoBillMapper;
import io.finer.erp.jeecg.stock.service.IScan2ndService;
import io.finer.erp.jeecg.stock.service.IScan3rdService;
import io.finer.erp.jeecg.stock.service.IScanService;
import io.finer.erp.jeecg.stock.service.IStkCheckBillService;
import io.finer.erp.jeecg.stock.service.IStkInventoryService;
import io.finer.erp.jeecg.stock.service.IStkIoBillEntryService;
import io.finer.erp.jeecg.stock.service.IStkIoBillService;
import io.finer.erp.jeecg.stock.service.IStkIoMaterialLogService;
import io.finer.erp.jeecg.stock.service.IStkPickUpBillService;
import io.finer.erp.jeecg.stock.service.IStkPickUpEntryService;
import io.finer.erp.jeecg.stock.service.IStkTrayDetailService;
import io.finer.erp.jeecg.stock.service.IStkTrayService;
import io.finer.erp.jeecg.stock.service.IZrkOrderProductMaterialLkService;
import io.finer.erp.jeecg.stock.util.ScanUtil;
import io.finer.erp.jeecg.stock.vo.InventoryVo;
import io.finer.erp.jeecg.stock.vo.ScanIO;
import io.finer.erp.jeecg.stock.vo.ScanInventory;
import lombok.extern.slf4j.Slf4j;

/**
 * @author duanyong
 * 2020-08-15
 * 扫码出入库service实现类
 */
@Service
@Slf4j
public class ScanServiceImpl implements IScanService {
	@Autowired
	private IBasMaterialService materialService;
	@Autowired
	private IBasMaterialCategoryService categoryService;
	@Autowired
	private IStkIoBillService ioBillService;
	@Autowired
	private IBasWarehouseService warehouseService;
	@Autowired
	private IStkInventoryService inventoryService;
	@Autowired
	private IBasCustomerService customerService;
	@Autowired
	private IStkCheckBillService checkBillService;
	@Autowired
	private IStkIoBillEntryService billEntryService;
	@Autowired
	private StkIoBillMapper billMapper;
	@Autowired
	private IBasMeasureUnitService unitService;
	@Autowired
	private IBasSupplierService supplierService;
	@Autowired
	private IStkIoBillService billService;
	@Autowired
	private IZrkShoporderService zrkShopOrderService;
	@Autowired
	private IZrkOrderProductService orderProductService;
	@Autowired
	private IStkIoMaterialLogService logService;
	@Autowired
	private IZrkOrderProcessService processService;
	@Autowired
	private IBasMaterialTempService materialTempService;
	@Autowired
	private IBasProductFormulaService formulaService;
	@Autowired
	private IStkTrayService trayService;
	@Autowired
	private IStkTrayDetailService trayDetailService;
	@Autowired
	private IZrkDeliverService deliverService;
	@Autowired
	private IScan2ndService scan2ndService;
	@Autowired
	private IStkPickUpBillService pickUpBillService;
	@Autowired
	private IStkPickUpEntryService pickUpEntryService;
	@Autowired
	private IZrkQzOrderService mesService;
	@Autowired
	private IScan3rdService scan3Service;
	@Autowired
	private IBasPfMaterialService pfMaterialService;
	@Autowired
	private IFinaPaymentService paymentService;
	@Autowired
	private ScanMapper scanMapper;
	@Autowired
	private ISysBaseAPI baseApi;
	@Autowired
	private BasMaterialCategoryMapper categoryMapper;
	@Autowired
	private IZzDeviceTypeService deviceTypeService;
	@Autowired
	private IZrkOrderProductMaterialLkService productMaterialLkService;
	
	private static final String BILL_STATUS = "12";
	public static final String BILL_STATUS_APPROVAL = "23";
	public static final String PRODUCTION_SOURCE_TYPE = "production_order";
	private static final String PURCHASE_ORDER_TYPE = "purchase_order";
	public static final String PROCESSING_ORDER_ENTRY_TYPE = "stk_io_bill.stk_io_bill_entry.";
	private static final String SALE_SOURCE_TYPE = "mall_bill";
	public static final List<String> inTypes = Arrays.asList("101", "1011", "199", "1991", "1993", "1992", "1994", "1995", "1997", "301");
	public static final List<String> outTypes = Arrays.asList("201", "299", "2011", "2991", "2992", "2993", "2997");

	/**
	 *  扫码后的出入库操作
	 * @author duanyong
	 * @param code 物料编码
	 * @param operType 1：入库 2：出库
	 * @param number 物料数量
	 * 2020-08-15
	 */
	@Override
	@Transactional
	public Result<JSONObject> inAndOut(ScanIO scanIo, Result<JSONObject> result) {
		synchronized(ScanServiceImpl.class) {
			String operType = scanIo.getOperType();
			String code = scanIo.getCode();
			boolean inFlag = false;
			boolean outFlag = false;
			for (String string : inTypes) {
				if (operType.equals(string)) {
					inFlag = true;
					break;
				}
			}
			for (String string : outTypes) {
				if (operType.equals(string)) {
					outFlag = true;
					break;
				}
			}
			//判断不能重复操作
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(code);
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500("不能重复操作");
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500("不能重复操作");
				}
			}
			//TODO
			//采购入库
			if ("101".equals(operType)) {
				return storage(scanIo, result);
			} else if ("1991".equals(operType)) {//生产入库(切张)
				return product(scanIo, result);
			} else if ("199".equals(operType)) {
				
			} else if ("1992".equals(operType)) {//(半成品入库)(复合)
				return hafeInFuhe(scanIo, result);
			} else if ("1993".equals(operType)) {//(半成品入库)(分切)
				return hafeInFenqie(scanIo, result);
			} else if ("201".equals(operType)) {//销售出库
				return saleOut(scanIo, result);
			} else if ("299".equals(operType)) {//其他出库
				
			} else if ("1994".equals(operType)) {//生产退库
				return rawMaterialIn(scanIo, result);
			} else if ("2991".equals(operType)) {//生产出库(复合)
				return materialOut(scanIo, result);
			} else if ("2992".equals(operType)) {//生产出库(分切)
				return materialOutFQ(scanIo, result);
			} else if ("2993".equals(operType)) {//生产出库(切张)
				return materialOutQZ(scanIo, result);
			} else if ("1995".equals(operType)) {//代加工入库
				return scan2ndService.processingIn(scanIo, result);
			} else if ("1997".equals(operType)) {//胶水入库
				return scan2ndService.glueIn(scanIo, result);
			} else if ("1998".equals(operType)) {//已有半成品入库
				return scan2ndService.existedHalfIn(scanIo, result);
			} else if ("2997".equals(operType)) {//胶水生产出库
				return scan3Service.glueOut(scanIo, result);
			}
			
			return result.error500("出入库类型错误");
		}
	}
	
	/**
	 * @Description 切张出库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-09-24 14:07:45
	 * @author: duanyong
	 * Revision:
	 *    2020-09-24 14:07:45 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> materialOutQZ(ScanIO scanIo, Result<JSONObject> result) {
		String orderNum = scanIo.getOrderNum();
		String list = scanIo.getList();
		//查询生产订单
		ZrkQzOrder mesOrder = this.mesService.getById(orderNum);
		List<String> codes = Lists.newArrayList();
		JSONArray array = JSONArray.parseArray(list);
		for (int i = 0; i < array.size(); i++) {
			JSONObject jsonObject = array.getJSONObject(i);
			codes.add(jsonObject.getString("code"));
		}
		List<BasMaterial> materials = materialService.getByCodes(codes);
		Date date = DateUtils.gettimestamp();
		if(materials == null || materials.size() == 0) {
			return result.error500("未找到相关物料。");
		}
		Boolean flag = scan3Service.checkIsFomula(materials, mesOrder.getId());
		if(!flag) {
			return result.error500("物料与配方不符");
		}
		
		//判断是否重复出库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		String prodId = mesOrder.getId();
		if(StringUtils.isNotBlank(mesOrder.getParentId())) {
			prodId = mesOrder.getParentId();
		}
		
		//验证提货单与扫码物料是否一致
		List<StkPickUpEntry> pickUpEntrys = scanMapper.getPickUpEntryByMes(prodId);
		List<String> pickUpCategoryIds = Lists.newArrayList();
		List<String> pickUpMaterialIds = Lists.newArrayList();
		if(CollUtil.isNotEmpty(pickUpEntrys)) {
			for(Iterator<StkPickUpEntry> iterator = pickUpEntrys.iterator(); iterator.hasNext();) {
				StkPickUpEntry entry = iterator.next();
				String categoryId = entry.getCategoryId();
				String materialId = entry.getMaterialId();
				if(StringUtils.isNotBlank(categoryId)) {
					pickUpCategoryIds.add(categoryId);
					List<BasMaterialCategory> childrenList = categoryMapper.getAllChildCategoryHasChild(categoryId);
					if(CollUtil.isNotEmpty(childrenList)){
						for(BasMaterialCategory basMaterialCategory : childrenList){
							pickUpCategoryIds.add(basMaterialCategory.getId());
						}
					}
				}
				if(StringUtils.isNotBlank(materialId)) {
					pickUpMaterialIds.add(materialId);
				}
			}
		}
		//验证提货单与扫码物料是否一致
		//判断不能重复操作
		Map<String, String> warehouseIdMap = Maps.newHashMap();
		for(Iterator<BasMaterial> iterator = materials.iterator(); iterator.hasNext();) {
			BasMaterial material = iterator.next();
			String code = material.getCode();
			List<StkInventory> inventorys = this.inventoryService.lambdaQuery()
					.eq(StkInventory::getMaterialId, material.getId()).gt(StkInventory::getQty, BigDecimal.ZERO).list();
			if(CollUtil.isEmpty(inventorys)) {
				return result.error500(new StringBuffer("编码为").append(code).append("的物料库存数为0。").toString());
			}
			StkInventory inventory = inventorys.get(0);
			String warehouseId = inventory.getWarehouseId();
			warehouseIdMap.put(material.getId(), warehouseId);
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(code);
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
			}
			String categoryId = material.getCategoryId();
			if(StringUtils.isNotBlank(categoryId) && !pickUpCategoryIds.contains(categoryId)) {
				String materialId = material.getId();
				if(!pickUpMaterialIds.contains(materialId)) {
					return result.error500(new StringBuffer("编号为").append(material.getCode()).append("的物料与提货单不符").toString());
				}
			}
		}
		
		String billNo = baseApi.getNoByCode("stock_io_bill_no");
		String stockIoType = scanIo.getOperType();
		String userName = scanIo.getUserName();
		StkIoBill bill = new StkIoBill();
		bill.setBillNo(billNo);
		bill.setStockIoType(stockIoType);
		bill.setBillDate(date);
		bill.setIsAuto(1);
		bill.setHasRp(0);
		bill.setClerkId(userName);
		bill.setHandlerId(userName);
		bill.setIsApproved(1);
		bill.setCreateBy(userName);
		bill.setCreateTime(date);
		bill.setIsRubric(0);
		bill.setIsClosed(0);
		bill.setBillProcStatus(BILL_STATUS_APPROVAL);
		bill.setSysOrgCode(scanIo.getOrgCode());
		bill.setRemark("切张扫码出库");
		bill.setSourceType(PRODUCTION_SOURCE_TYPE);
		bill.setSourceId(mesOrder.getId());
		bill.setSourceNo(mesOrder.getCode());
		
		int entryNum = 1;
		List<StkIoBillEntry> entryList = Lists.newLinkedList();
		Map<String, BasMaterial> materialMap = Maps.newHashMap();
		for (BasMaterial material : materials) {
			materialMap.put(material.getId(), material);
			bill.setSupplierId(material.getSupplier());
			//取出物料最近的出入库单
			List<StkIoBill> ioBillList = this.billMapper.getIoBillByMaterial(material.getId());
			StkIoBill bill1 = ioBillList.get(0);
			//获取之前的入库信息
			LambdaQueryWrapper<StkIoBillEntry> entryQuery = new LambdaQueryWrapper<>();
			entryQuery.eq(StkIoBillEntry::getMid, bill1.getId());
			entryQuery.eq(StkIoBillEntry::getMaterialId, material.getId());
			List<StkIoBillEntry> inEntrys = this.billEntryService.list(entryQuery);
			StkIoBillEntry inEntry = inEntrys.get(0);
			//判断库存中的物料
			BigDecimal checkNumber = inEntry.getQty();
			String batchNo = inEntry.getBatchNo();
			;
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(billNo);
			billEntry.setMid(bill.getId());
			billEntry.setBatchNo(batchNo);
			billEntry.setQty(checkNumber);
			billEntry.setSourceType(PROCESSING_ORDER_ENTRY_TYPE + bill1.getStockIoType());
			billEntry.setSourceEntryId(inEntry.getId());
			billEntry.setUnitId(material.getUnitId());
			String warehouseId = warehouseIdMap.get(material.getId());
			if(StringUtils.isBlank(warehouseId)) {
				return result.error500(new StringBuffer("未找到编号为").append(material.getCode()).append("的物料所在仓库").toString());
			}
			billEntry.setWarehouseId(warehouseId);
			billEntry.setSettleQty(checkNumber);
			billEntry.setInventoryQty(checkNumber);
			billEntry.setWidth(material.getWidth());
			billEntry.setLength(material.getLength());
			billEntry.setSourceEntryNo(batchNo);
//			billEntry.setCost(inEntry.getCost());
			billEntry.setInventoryUnitId(inEntry.getUnitId());
			billEntry.setEntryNo(entryNum);
			billEntry.setCost(inEntry.getCost());
			entryList.add(billEntry);
			entryNum ++;
		}
		this.ioBillService.saveMain(bill, entryList);
		this.ioBillService.updateInventory(bill, entryList);
		for (StkIoBillEntry stkIoBillEntry : entryList) {
			BasMaterial material = materialMap.get(stkIoBillEntry.getMaterialId());
			logService.insertLog(bill.getId(), date, stkIoBillEntry.getId(), bill.getStockIoType(), 0, material, stkIoBillEntry.getUnitId(), mesOrder.getId(), 2, stkIoBillEntry.getCost(), stkIoBillEntry.getQty(), mesOrder.getId());
			scan2ndService.changePickUpEntryIsOut(material.getId(), scanIo.getProcedureId());
		}
		//查询出库是否完成
		this.scan3Service.checkOutComplete(mesOrder.getId());
		log.info("切张出库完成" + bill.getBillNo());
		return result.success("切张出库完成");
	}

	/**
	 * @Description 分切出库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-09-24 09:48:23
	 * @author: duanyong
	 * Revision:
	 *    2020-09-24 09:48:23 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> materialOutFQ(ScanIO scanIo, Result<JSONObject> result) {
		String orderNum = scanIo.getOrderNum();
		String list = scanIo.getList();
		//查询生产订单
		ZrkQzOrder mesOrder = this.mesService.getById(orderNum);
		List<String> codes = Lists.newArrayList();
		JSONArray array = JSONArray.parseArray(list);
		for (int i = 0; i < array.size(); i++) {
			JSONObject jsonObject = array.getJSONObject(i);
			codes.add(jsonObject.getString("code"));
		}
		List<BasMaterial> materials = materialService.getByCodes(codes);
		Date date = DateUtils.gettimestamp();
		if(materials == null || materials.size() == 0) {
			return result.error500("未找到相关物料。");
		}
		Boolean flag = scan3Service.checkIsFomula(materials, mesOrder.getId());
		if(!flag) {
			return result.error500("物料与配方不符");
		}
		
		//判断是否重复出库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		String prodId = mesOrder.getId();
		if(StringUtils.isNotBlank(mesOrder.getParentId())) {
			prodId = mesOrder.getParentId();
		}
		
		//验证提货单与扫码物料是否一致
		List<StkPickUpEntry> pickUpEntrys = scanMapper.getPickUpEntryByMes(prodId);
		List<String> pickUpCategoryIds = Lists.newArrayList();
		List<String> pickUpMaterialIds = Lists.newArrayList();
		if(CollUtil.isNotEmpty(pickUpEntrys)) {
			for(Iterator<StkPickUpEntry> iterator = pickUpEntrys.iterator(); iterator.hasNext();) {
				StkPickUpEntry entry = iterator.next();
				String categoryId = entry.getCategoryId();
				String materialId = entry.getMaterialId();
				if(StringUtils.isNotBlank(categoryId)) {
					pickUpCategoryIds.add(categoryId);
					List<BasMaterialCategory> childrenList = categoryMapper.getAllChildCategoryHasChild(categoryId);
					if(CollUtil.isNotEmpty(childrenList)){
						for(BasMaterialCategory basMaterialCategory : childrenList){
							pickUpCategoryIds.add(basMaterialCategory.getId());
						}
					}
				}
				if(StringUtils.isNotBlank(materialId)) {
					pickUpMaterialIds.add(materialId);
				}
			}
		}
		//验证提货单与扫码物料是否一致
		//判断不能重复操作
		Map<String, String> warehouseIdMap = Maps.newHashMap();
		for(Iterator<BasMaterial> iterator = materials.iterator(); iterator.hasNext();) {
			BasMaterial material = iterator.next();
			String code = material.getCode();
			List<StkInventory> inventorys = this.inventoryService.lambdaQuery()
					.eq(StkInventory::getMaterialId, material.getId()).gt(StkInventory::getQty, BigDecimal.ZERO).list();
			if(CollUtil.isEmpty(inventorys)) {
				return result.error500(new StringBuffer("编码为").append(code).append("的物料库存数为0。").toString());
			}
			StkInventory inventory = inventorys.get(0);
			String warehouseId = inventory.getWarehouseId();
			warehouseIdMap.put(material.getId(), warehouseId);
			
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(code);
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
			}
			String categoryId = material.getCategoryId();
			if(StringUtils.isNotBlank(categoryId) && !pickUpCategoryIds.contains(categoryId)) {
				String materialId = material.getId();
				if(!pickUpMaterialIds.contains(materialId)) {
					return result.error500(new StringBuffer("编号为").append(material.getCode()).append("的物料与提货单不符").toString());
				}
			}
		}
		
		String billNo = baseApi.getNoByCode("stock_io_bill_no");
		String stockIoType = scanIo.getOperType();
		String userName = scanIo.getUserName();
		StkIoBill bill = new StkIoBill();
		bill.setBillNo(billNo);
		bill.setStockIoType(stockIoType);
		bill.setBillDate(date);
		bill.setIsAuto(1);
		bill.setHasRp(0);
		bill.setClerkId(userName);
		bill.setHandlerId(userName);
		bill.setIsApproved(1);
		bill.setCreateBy(userName);
		bill.setCreateTime(date);
		bill.setIsRubric(0);
		bill.setIsClosed(0);
		bill.setBillProcStatus(BILL_STATUS_APPROVAL);
		bill.setSysOrgCode(scanIo.getOrgCode());
		bill.setRemark("分切扫码出库");
		bill.setSourceType(PRODUCTION_SOURCE_TYPE);
		bill.setSourceId(mesOrder.getId());
		bill.setSourceNo(mesOrder.getCode());
		
		int entryNum = 1;
		List<StkIoBillEntry> entryList = Lists.newLinkedList();
		Map<String, BasMaterial> materialMap = Maps.newHashMap();
		for (BasMaterial material : materials) {
			materialMap.put(material.getId(), material);
			bill.setSupplierId(material.getSupplier());
			//取出物料最近的出入库单
			List<StkIoBill> ioBillList = this.billMapper.getIoBillByMaterial(material.getId());
			StkIoBill bill1 = ioBillList.get(0);
			//获取之前的入库信息
			LambdaQueryWrapper<StkIoBillEntry> entryQuery = new LambdaQueryWrapper<>();
			entryQuery.eq(StkIoBillEntry::getMid, bill1.getId());
			entryQuery.eq(StkIoBillEntry::getMaterialId, material.getId());
			List<StkIoBillEntry> inEntrys = this.billEntryService.list(entryQuery);
			StkIoBillEntry inEntry = inEntrys.get(0);
			//判断库存中的物料
			BigDecimal checkNumber = inEntry.getQty();
			String batchNo = inEntry.getBatchNo();
			;
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(billNo);
			billEntry.setMid(bill.getId());
			billEntry.setBatchNo(batchNo);
			billEntry.setQty(checkNumber);
			billEntry.setSourceType(PROCESSING_ORDER_ENTRY_TYPE + bill1.getStockIoType());
			billEntry.setSourceEntryId(inEntry.getId());
			billEntry.setUnitId(material.getUnitId());
			String warehouseId = warehouseIdMap.get(material.getId());
			if(StringUtils.isBlank(warehouseId)) {
				return result.error500(new StringBuffer("未找到编号为").append(material.getCode()).append("的物料所在仓库").toString());
			}
			billEntry.setWarehouseId(warehouseId);
			billEntry.setSettleQty(checkNumber);
			billEntry.setInventoryQty(checkNumber);
			billEntry.setWidth(material.getWidth());
			billEntry.setLength(material.getLength());
			billEntry.setSourceEntryNo(batchNo);
//			billEntry.setCost(inEntry.getCost());
			billEntry.setInventoryUnitId(inEntry.getUnitId());
			billEntry.setEntryNo(entryNum);
			billEntry.setCost(inEntry.getCost());
			entryList.add(billEntry);
			entryNum ++;
		}
		this.ioBillService.saveMain(bill, entryList);
		this.ioBillService.updateInventory(bill, entryList);
		if(StringUtils.isNotBlank(mesOrder.getParentId())) {
			prodId = mesOrder.getParentId();
		}
		for (StkIoBillEntry stkIoBillEntry : entryList) {
			BasMaterial material = materialMap.get(stkIoBillEntry.getMaterialId());
			logService.insertLog(bill.getId(), date, stkIoBillEntry.getId(), bill.getStockIoType(), 0, material, stkIoBillEntry.getUnitId(), mesOrder.getId(), 2, stkIoBillEntry.getCost(), stkIoBillEntry.getQty(), prodId);
			scan2ndService.changePickUpEntryIsOut(material.getId(), scanIo.getProcedureId());
		}
		
		//检测是否出库完成
		this.scan3Service.checkOutComplete(mesOrder.getId());
		log.info("分切出库完成" + bill.getBillNo());
		return result.success("分切出库完成");
	}
	
	/**
	 * @Description 生产出库(复合)
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-08-22 17:25:57
	 * @author: duanyong
	 * Revision:
	 *    2020-08-22 17:25:57 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> materialOut(ScanIO scanIo, Result<JSONObject> result){
		String orderNum = scanIo.getOrderNum();
		String list = scanIo.getList();
		//查询MES单
		ZrkQzOrder mesOrder = this.mesService.getById(orderNum);
		List<String> codes = Lists.newArrayList();
		JSONArray array = JSONArray.parseArray(list);
		for (int i = 0; i < array.size(); i++) {
			JSONObject jsonObject = array.getJSONObject(i);
			codes.add(jsonObject.getString("code"));
		}
		List<BasMaterial> materials = materialService.getByCodes(codes);
		if(CollUtil.isEmpty(materials)) {
			return result.error500("未查到相关编码的物料信息。");
		}
		Boolean flag = scan3Service.checkIsFomula(materials, mesOrder.getId());
		if(!flag) {
			return result.error500("物料与配方不符");
		}
		//判断是否重复出库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		String prodId = mesOrder.getId();
		if(StringUtils.isNotBlank(mesOrder.getParentId())) {
			prodId = mesOrder.getParentId();
		}
		
		//验证提货单与扫码物料是否一致
		List<StkPickUpEntry> pickUpEntrys = scanMapper.getPickUpEntryByMes(prodId);
		List<String> pickUpCategoryIds = Lists.newArrayList();
		List<String> pickUpMaterialIds = Lists.newArrayList();
		if(CollUtil.isNotEmpty(pickUpEntrys)) {
			for(Iterator<StkPickUpEntry> iterator = pickUpEntrys.iterator(); iterator.hasNext();) {
				StkPickUpEntry entry = iterator.next();
				String categoryId = entry.getCategoryId();
				String materialId = entry.getMaterialId();
				if(StringUtils.isNotBlank(categoryId)) {
					pickUpCategoryIds.add(categoryId);
					List<BasMaterialCategory> childrenList = categoryMapper.getAllChildCategoryHasChild(categoryId);
					if(CollUtil.isNotEmpty(childrenList)){
						for(BasMaterialCategory basMaterialCategory : childrenList){
							pickUpCategoryIds.add(basMaterialCategory.getId());
						}
					}
				}
				if(StringUtils.isNotBlank(materialId)) {
					pickUpMaterialIds.add(materialId);
				}
			}
		}
		//验证提货单与扫码物料是否一致
		//判断不能重复操作
		Map<String, String> warehouseIdMap = Maps.newHashMap();
		for(Iterator<BasMaterial> iterator = materials.iterator(); iterator.hasNext();) {
			BasMaterial material = iterator.next();
			String code = material.getCode();
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(code);
			List<StkInventory> inventorys = this.inventoryService.lambdaQuery()
					.eq(StkInventory::getMaterialId, material.getId()).gt(StkInventory::getQty, BigDecimal.ZERO).list();
			if(CollUtil.isEmpty(inventorys)) {
				return result.error500(new StringBuffer("编码为").append(code).append("的物料库存数为0。").toString());
			}
			StkInventory inventory = inventorys.get(0);
			String warehouseId = inventory.getWarehouseId();
			warehouseIdMap.put(material.getId(), warehouseId);
			//获取所在仓库
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("编码为").append(code).append("的物料已出库，不能重复操作").toString());
				}
			}
			String categoryId = material.getCategoryId();
			if(StringUtils.isNotBlank(categoryId) && !pickUpCategoryIds.contains(categoryId)) {
				String materialId = material.getId();
				if(!pickUpMaterialIds.contains(materialId)) {
					return result.error500(new StringBuffer("编号为").append(material.getCode()).append("的物料与提货单不符").toString());
				}
			}
		}
		
		Date date = DateUtils.gettimestamp();
		String billNo = baseApi.getNoByCode("stock_io_bill_no");
		String stockIoType = scanIo.getOperType();
		String userName = scanIo.getUserName();
		StkIoBill bill = new StkIoBill();
		bill.setBillNo(billNo);
		bill.setStockIoType(stockIoType);
		bill.setBillDate(date);
		bill.setIsAuto(1);
		bill.setHasRp(0);
		bill.setClerkId(userName);
		bill.setHandlerId(userName);
//		bill.setApproverId(userName);
		bill.setIsApproved(1);
		bill.setCreateBy(userName);
		bill.setCreateTime(date);
		bill.setIsRubric(0);
		bill.setIsClosed(0);
		bill.setBillProcStatus(BILL_STATUS_APPROVAL);
		bill.setSysOrgCode(scanIo.getOrgCode());
		bill.setRemark("物料扫码出库");
		bill.setSourceType("production_order");
		bill.setSourceId(mesOrder.getId());
		bill.setSourceNo(mesOrder.getCode());
		List<StkIoBillEntry> entrys = Lists.newArrayList();
		Map<String, BasMaterial> materialMap = Maps.newHashMap();
		int num = 1;
		for (BasMaterial material : materials) {
			bill.setSupplierId(material.getSupplier());
			materialMap.put(material.getId(), material);
			//取出物料最近的入库单
			List<StkIoBill> ioBillList = this.billMapper.getIoBillByMaterial(material.getId());
			StkIoBill bill1 = ioBillList.get(0);
			//获取之前的入库信息
			LambdaQueryWrapper<StkIoBillEntry> entryQuery = new LambdaQueryWrapper<>();
			entryQuery.eq(StkIoBillEntry::getMid, bill1.getId());
			entryQuery.eq(StkIoBillEntry::getMaterialId, material.getId());
			List<StkIoBillEntry> inEntrys = this.billEntryService.list(entryQuery);
			StkIoBillEntry inEntry = inEntrys.get(0);
			//判断库存中的物料
			BigDecimal checkNumber = inEntry.getQty();
			String batchNo = inEntry.getBatchNo();
			
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(billNo);
			billEntry.setMid(bill.getId());
//			billEntry.setBatchNo(billNo + "-10");
			billEntry.setQty(checkNumber);
			billEntry.setUnitId(material.getUnitId());
			String warehouseId = warehouseIdMap.get(material.getId());
			if(StringUtils.isBlank(warehouseId)) {
				return result.error500(new StringBuffer("未找到编号为").append(material.getCode()).append("的物料所在仓库").toString());
			}
			billEntry.setWarehouseId(warehouseId);
			billEntry.setSettleQty(checkNumber);
			billEntry.setInventoryQty(checkNumber);
			billEntry.setCost(inEntry.getCost());
			billEntry.setInventoryUnitId(inEntry.getUnitId());
			billEntry.setEntryNo(num);
			billEntry.setSourceEntryId(inEntry.getId());
			billEntry.setSourceType(PROCESSING_ORDER_ENTRY_TYPE + bill1.getStockIoType());
			if(null != inEntry.getEntryNo()) {
				billEntry.setSourceEntryNo(inEntry.getEntryNo().toString());
			}
			billEntry.setBatchNo(batchNo);
			entrys.add(billEntry);
			num ++;
		}
		this.billService.saveMain(bill, entrys);
		this.billService.updateInventory(bill, entrys);
		for (StkIoBillEntry en : entrys) {
			BasMaterial mate = materialMap.get(en.getMaterialId());
			logService.insertLog(bill.getId(), date, en.getId(), stockIoType, 0, mate, mate.getUnitId(), mesOrder.getId(), 2, en.getCost(), en.getQty(), mesOrder.getId());
			scan2ndService.changePickUpEntryIsOut(mate.getId(), scanIo.getProcedureId());
		}
		//检测是否出货完成
		this.scan3Service.checkOutComplete(mesOrder.getId());
		
		log.info("复合出库完成" + bill.getBillNo());
		return result.success("复合出库完成");
	}

	/**
	 * @Description 生产退库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-09-23 15:05:50
	 * @author: duanyong
	 * Revision:
	 *    2020-09-23 15:05:50 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> rawMaterialIn(ScanIO scanIo, Result<JSONObject> result) {
		// TODO Auto-generated method stub
		String code = scanIo.getCode();
		BasMaterial material = this.materialService.getMaterialByCode(code);
		if (null == material) {
			return result.error500("未查询到该物料");
		}
		
		//判断产品数量
		String numberStr = scanIo.getNumber();
		if (StringUtils.isBlank(scanIo.getNumber())) {
			return result.error500("未传入产品数量");
		}
		BigDecimal number = new BigDecimal(numberStr);
		String unitId = scanIo.getUnit();
		if(StringUtils.isBlank(unitId)) {
			return result.error500("未传入物料单位");
		}
		BasMeasureUnit unit = this.unitService.getById(unitId);
		if(null == unit) {
			return result.error500("未找到物料单位");
		}
		//取出长宽
		BigDecimal length = scanIo.getLength();
		BigDecimal width = scanIo.getWidth();
		//获得物料出库时的MES单号和仓库
		//获得MES单号
		String materialId = material.getId();
		//查询该物料的所有出入库记录
		List<StkIoBill> billList = this.billMapper.getByMaterialId(materialId);
		if(CollUtil.isEmpty(billList)) {
			return result.error500("未找到该物料的出入库记录");
		}
		Iterator<StkIoBill> it = billList.iterator();
		StkIoBill outBill = null;
		//记录生产出库的四种类型
		List<String> productOutTypes = CollUtil.newArrayList("2991", "2992", "2993", "2997");
		while(it.hasNext()) {
			StkIoBill bill = it.next();
			if(productOutTypes.contains(bill.getStockIoType())) {
				//判断出库类型，找到物料的出库记录
				outBill = bill;
				break;
			}
		}
		if(null == outBill) {
			return result.error500("未找到该物料的出库记录");
		}
		String mesCode = outBill.getSourceNo();
		String mesId = outBill.getSourceId();
		ZrkQzOrder mes = mesService.getById(mesId);
		if(null == mes) {
			List<ZrkQzOrder> meses = this.mesService.lambdaQuery().eq(ZrkQzOrder::getCode, mesCode).list();
			if(CollUtil.isEmpty(meses)) {
				return result.error500("未找到相关的mes单信息");
			}
			mes = meses.get(0);
		}
		mesId = mes.getId();
		//获得物料出库时的仓库
		List<StkIoBillEntry> entrys = this.billEntryService.lambdaQuery().eq(StkIoBillEntry::getMid, outBill.getId()).eq(StkIoBillEntry::getMaterialId, materialId).list();
		if(CollUtil.isEmpty(entrys)) {
			return result.error500("未找到该物料的出库明细");
		}
		StkIoBillEntry entry = entrys.get(0);
		String warehouseId = entry.getWarehouseId();
		//表单项验证
		if (null != length && length.compareTo(BigDecimal.ZERO) <= 0) {
			return result.error500("请输入正确的长度");
		}
		if (null != width && width.compareTo(BigDecimal.ZERO) <= 0) {
			return result.error500("请输入正确的宽度");
		}
		//封装出入库记录
		StkIoMaterialLog ioLog = StkIoMaterialLog.builder()
				.materialId(material.getId())
				.ioType(scanIo.getOperType())
				.procedureId(mesId)
				.amount(number).build();
		BigDecimal cost = scan2ndService.getMaterialCost(ioLog);
		if(cost == null) {
			cost = BigDecimal.ZERO;
		}
		//检查退库数量不能比原数量大
		BasMaterialTemp materialTemp = this.materialTempService.getByCode(code);
		if(materialTemp != null) {
			BigDecimal tempAmount = materialTemp.getAmount();
			if(tempAmount != null) {
				if(tempAmount.compareTo(number) < 0) {
					return result.error500("物料数量不能大于原数量");
				}
			}
		}
		
		//计算物料平方数
		BigDecimal square = null;
		if ("吨".equals(unit.getName())) {
			BigDecimal outQty = entry.getQty();
			BigDecimal preSquare = material.getSquare();
			if(null != preSquare && null != outQty) {
				square = number.divide(outQty, 10, BigDecimal.ROUND_DOWN).multiply(preSquare);
				square = square.setScale(4, BigDecimal.ROUND_DOWN);
			} else {
				if(null != width && null != length) {
					square = width.divide(new BigDecimal(100), 4, BigDecimal.ROUND_DOWN).multiply(length);
					square.setScale(2, BigDecimal.ROUND_DOWN);
					String model = width.toString() + "*" + length.toString();
					material.setModel(model);
				}
			}
		} else if ("平方".equals(unit.getName())) {
			square = number;
			if(null != width && null != length) {
				String model = width.toString() + "*" + length.toString();
				material.setModel(model);
			}
		} else {
			if(null != width && null != length) {
				square = width.divide(new BigDecimal(100), 4, BigDecimal.ROUND_DOWN).multiply(length);
				square.setScale(2, BigDecimal.ROUND_DOWN);
				String model = width.toString() + "*" + length.toString();
				material.setModel(model);
			}
		}
		
		//物料信息维护
		material.setLength(scanIo.getLength());
		material.setWidth(scanIo.getWidth());
		material.setUnitId(unit.getId());
		material.setModel(scanIo.getModel());
		material.setSquare(square);
		this.materialService.updateById(material);
		//维护物料数量
		materialTemp.setAmount(number);
		this.materialTempService.updateById(materialTemp);
		
		Date date = DateUtils.gettimestamp();
		String billNo = baseApi.getNoByCode("stock_io_bill_no");
		String stockIoType = scanIo.getOperType();
		String userName = scanIo.getUserName();
		//封装复合半成品入库单信息
		StkIoBill bill = new StkIoBill();
		bill.setBillNo(billNo);
		bill.setStockIoType(stockIoType);
		bill.setBillDate(date);
		bill.setIsAuto(1);
		bill.setClerkId(userName);
		bill.setHandlerId(userName);
		bill.setIsApproved(1);
		bill.setCreateBy(userName);
		bill.setCreateTime(date);
		bill.setIsRubric(0);
		bill.setSourceType(PRODUCTION_SOURCE_TYPE);
		bill.setSourceId(mesId);
		bill.setSourceNo(mesCode);
		bill.setBillProcStatus(BILL_STATUS_APPROVAL);
		bill.setSysOrgCode(scanIo.getOrgCode());
		bill.setSupplierId(CommonConstant.QY_SUPPLIER_ID);
		bill.setRemark("生产退库");
		
		StkIoBillEntry billEntry = new StkIoBillEntry();
		billEntry.setMaterialId(material.getId());
		billEntry.setBillNo(billNo);
		billEntry.setMid(bill.getId());
		billEntry.setBatchNo(billNo + "-10");
		billEntry.setQty(number);
		billEntry.setCost(cost);
		if(width != null) {
			billEntry.setWidth(width);
		}
		if(length != null) {
			billEntry.setLength(length);
		}
		billEntry.setUnitId(material.getUnitId());
		billEntry.setWarehouseId(warehouseId);
		billEntry.setSettleQty(number);
		billEntry.setEntryNo(1);
		
		List<StkIoBillEntry> entryList = new LinkedList<>();
		entryList.add(billEntry);
		this.ioBillService.saveMain(bill, entryList);
		this.ioBillService.updateInventory(bill, entryList);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("name", material.getName());
		jsonObject.put("unit", unit.getName());
		jsonObject.put("model", material.getModel());
		jsonObject.put("num", scanIo.getNumber());
		jsonObject.put("length", material.getLength());
		jsonObject.put("width", material.getWidth());
		jsonObject.put("type", "1992");
		if(square != null) {
			jsonObject.put("square", square);
		}
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		result.setResult(jsonObject);
		
		logService.insertLog(bill.getId(), date, billEntry.getId(), bill.getStockIoType(), 0, material, unitId, mesId, 1, cost, billEntry.getQty(), mesId);
		log.info("生产退库完成" + bill.getBillNo());
		return result;
	}

	/**
	 * @Description 采购入库
	 * @param scanIo PDA设备传入的参数
	 * @return 
	 * Create at: 2020-08-15 17:17:36
	 * @author: duanyong
	 * Revision:
	 *    2020-08-15 17:17:36 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> storage(ScanIO scanIo, Result<JSONObject> result) {
		//根据物料编码查询物料，并比对物料数量
		BasMaterial material = this.getMaterialByCode(scanIo.getCode());
		String materialId = scanIo.getMaterialId();
		if (null != materialId && !materialId.equals(material.getId())) {
			return result.error500("物料信息错误");
		}
		if (StringUtils.isBlank(scanIo.getNumber())) {
			return result.error500("未传入物料数量");
		}
		if(StringUtils.isBlank(scanIo.getNumber())) {
			return result.error500("未获取到入库数量");
		}
		String orderNum = scanIo.getOrderNum();
		if (StringUtils.isBlank(orderNum)) {
			return scan2ndService.tempStorage(scanIo, result);
//			return result.error500("未传入采购单");
		}
		StkIoBill purchaseOrder = this.billService.getById(orderNum);
		if (null == purchaseOrder) {
			return result.error500("传入的采购单与数据库中的采购单不符");
		}
		

		BigDecimal checkNumber = new BigDecimal(scanIo.getNumber());//获取物料数量
		String categoryId = material.getCategoryId();
		//查询采购单明细用于比对
		LambdaQueryWrapper<StkIoBillEntry> entryQuery = new LambdaQueryWrapper<>();
		entryQuery.eq(StkIoBillEntry::getMid, orderNum);
		List<StkIoBillEntry> billEntrys = this.billEntryService.list(entryQuery);
		if (null == billEntrys || 0 == billEntrys.size()) {
			return result.error500("该采购单中未发现物料的采购明细，请检查");
		}
		//判断要入库的物料是否跟采购单上的物料分类对应
		BigDecimal purchaseQty = BigDecimal.ZERO;
		BigDecimal purchaseLength = BigDecimal.ZERO;
		BigDecimal purchaseCost = BigDecimal.ZERO;
		boolean categoryFlag = false;
		boolean unitFlag = false;
		StkIoBillEntry stkIoBillEntry = null;
		for (StkIoBillEntry entry : billEntrys) {
			String entryCategoryId = entry.getMaterialId();//（采购单的entry中的materialId变量存储的是物料分类ID）
			if(entryCategoryId.equals(categoryId)) {
				categoryFlag = true;
				stkIoBillEntry = entry;
				entry.getSettlePrice();
				if(entry.getUnitId().equals(scanIo.getUnit())) {
					unitFlag = true;
				}
				if(entry.getQty() != null) {
					purchaseQty = purchaseQty.add(entry.getQty());
				}
				if(entry.getLength() != null) {
					purchaseLength = purchaseLength.add(entry.getLength());
				}
				if(entry.getCost() != null) {
					purchaseCost = purchaseCost.add(entry.getCost());
				}
			}
		}
		if(!categoryFlag) {
			return result.error500("入库物料与采购单不符，请核对后再入库");
		}
		if(!unitFlag) {
			return result.error500("入库单位与采购单不符，请核对后再入库");
		}
		//查询已经生成的对应该采购单的采购入库明细。检查数据是否与采购单相符。
		List<StkIoBillEntry> inEntrys = this.billEntryService.getPurchaseOrderEntry(purchaseOrder.getBillNo());
		if(null != inEntrys && 0 != inEntrys.size()) {
			List<String> mIDs = Lists.newArrayList();
			for (StkIoBillEntry entry : inEntrys) {
				mIDs.add(entry.getMaterialId());
			}
			List<BasMaterial> ms = this.materialService.getByIds(mIDs);
			Map<String, BasMaterial> map = Maps.newLinkedHashMap();
			for (BasMaterial basMaterial : ms) {
				map.put(basMaterial.getId(), basMaterial);
			}
			BigDecimal subNumber = BigDecimal.ZERO;
			BigDecimal subLength = BigDecimal.ZERO;
			BigDecimal subCost = BigDecimal.ZERO;
			for (StkIoBillEntry entry : inEntrys) {
				BasMaterial mate = map.get(entry.getMaterialId());
				if(material.getCategoryId().equals(mate.getCategoryId())) {
					subNumber = subNumber.add(entry.getQty());
					if(entry.getLength() != null) {
						subLength = subLength.add(entry.getLength());
					}
					if(entry.getCost() != null) {
						subCost = subCost.add(entry.getCost());
					}
				}
			}
			if(scanIo.getLength() != null) {
				subLength = subLength.add(scanIo.getLength());
			}
			subNumber = subNumber.add(checkNumber);
			if(scanIo.getAmount() != null) {
				subCost = subCost.add(scanIo.getAmount());
			}
			if(subNumber.compareTo(purchaseQty) > 0) {
				return result.error500("入库数量超过采购数量，请核对后再入库");
			}
//			if(subLength.compareTo(purchaseLength) > 0) {
//				return result.error500("入库长度已经超过采购长度，请核对后再入库");
//			}
			if(subCost.compareTo(purchaseCost) > 0) {
				return result.error500("入库成本超过采购成本，请核对后再入库");
			}
		}
		
		//获取物料采购单明细
		if(stkIoBillEntry == null) {
			return result.error500("入库物料与采购单不符，请核对后再入库");
		}
		//检查物料成本
		BigDecimal cost = scanIo.getAmount();
		if (!stkIoBillEntry.getUnitId().equals(scanIo.getUnit())) {
			return result.error500("输入的单位与采购单上的单位不符，请核对后再入库");
		}
		//物料信息维护
		material.setUnitId(stkIoBillEntry.getUnitId());
		material.setSupplier(purchaseOrder.getSupplierId());
		if(StringUtils.isNotBlank(scanIo.getModel())) {
			material.setModel(scanIo.getModel());
		}
		material.setSalePrice(null);
		BigDecimal length = scanIo.getLength();
		if(null != length) {
			material.setLength(length);
		}
		BigDecimal width = scanIo.getWidth();
		if(null != width) {
			material.setWidth(width);
		}
		//吨转平方
		BasMeasureUnit unit = unitService.getById(material.getUnitId());
		if("吨".equals(unit.getName())) {
			BigDecimal square = this.categoryService.getSquare(checkNumber, categoryId);
			material.setSquare(square);
		}
		if("平方".equals(unit.getName())) {
			material.setSquare(checkNumber);
		}
		this.materialService.updateById(material);
		List<StkIoBill> billList = this.billService.getPurchaseIoBill(purchaseOrder.getBillNo());
		//查询是否已经有采购入库单满足条件，可以直接在后面添加明细，如果不存在，则新增一条采购入库单
		StkIoBill existIoBill = null;
		if(null != billList && 0 != billList.size()) {
			for (StkIoBill stkIoBill : billList) {
				String status = StringUtils.rightPad(stkIoBill.getBillProcStatus(), 3, "0");
				if(Integer.parseInt(status) < 200) {
					existIoBill = stkIoBill;
					break;
				}
			}
		}
		Date date = DateUtils.getDate();
		if(existIoBill != null) {
			List<StkIoBillEntry> entrys = this.billEntryService.selectByMainId(existIoBill.getId());
			int maxBatchNo = 0;
			int maxEntryNo = 0;
			for (StkIoBillEntry stkIoBillEntry2 : entrys) {
				String batchNo = stkIoBillEntry2.getBatchNo();
				String[] nos = batchNo.split("-");
				String no = nos[nos.length-1];
				int num = 0;
				try {
					num = Integer.parseInt(no);
				} catch (Exception e) {
				}
				if(num > maxBatchNo) {
					maxBatchNo = num;
				}
				if(stkIoBillEntry2.getEntryNo() > maxEntryNo) {
					maxEntryNo = stkIoBillEntry2.getEntryNo();
				}
			}
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(existIoBill.getBillNo());
			billEntry.setMid(existIoBill.getId());
			maxBatchNo = maxBatchNo + 10;
			billEntry.setBatchNo(existIoBill.getBillNo() + "-" + maxBatchNo);
			billEntry.setQty(checkNumber);
			billEntry.setSourceType(existIoBill.getSourceType());
			billEntry.setSourceEntryNo(stkIoBillEntry.getEntryNo().toString());
			billEntry.setSourceEntryId(stkIoBillEntry.getId());
			if(null != width) {
				billEntry.setWidth(width);
			}
			billEntry.setLength(length);
			billEntry.setUnitId(material.getUnitId());
			billEntry.setWarehouseId(scanIo.getWarehouseId());
			billEntry.setSettleQty(checkNumber);
			billEntry.setEntryNo(maxEntryNo + 1);
			if(null == cost) {
				//计算成本
				cost = scan2ndService.computingStorageCosts(purchaseOrder, material, checkNumber);
			}
			billEntry.setCost(cost);
			BigDecimal settlePrice = cost.divide(checkNumber, 2, BigDecimal.ROUND_DOWN);
			billEntry.setSettlePrice(settlePrice);
			billEntry.setSettleAmt(cost);
			billEntry.setSettleQty(checkNumber);
			billEntry.setSupplierId(purchaseOrder.getSupplierId());
//			billEntry.setSettlePrice(materialPrice);
			entrys.add(billEntry);
			//采购单是否开票
			existIoBill.setIsInvoice(purchaseOrder.getIsInvoice());
			this.ioBillService.updateMain(existIoBill, entrys);
			this.inventoryService.increase(billEntry);//入库完成添加实时库存
			paymentService.createPayable(existIoBill,billEntry);//生成应付账单
			logService.insertLog(existIoBill.getId(), date, billEntry.getId(), existIoBill.getStockIoType(), 0, material, unit.getId(), purchaseOrder.getId(), 1, cost, billEntry.getQty(), scanIo.getProcedureId());
		} else {
			String billNo = baseApi.getNoByCode("stock_io_bill_no");
			String stockIoType = scanIo.getOperType();
			String userName = scanIo.getUserName();
			StkIoBill bill = new StkIoBill();
			bill.setBillNo(billNo);
			bill.setStockIoType(stockIoType);
			bill.setBillDate(date);
			bill.setIsAuto(1);
			bill.setClerkId(userName);
			bill.setHandlerId(userName);
			bill.setIsApproved(0);//是否通过 需要手动审批
			bill.setCreateBy(userName);
			bill.setCreateTime(date);
			bill.setIsRubric(0);
			bill.setHasRp(1);
			bill.setSourceType(PURCHASE_ORDER_TYPE);
			bill.setSourceId(purchaseOrder.getId());
			bill.setSourceNo(purchaseOrder.getBillNo());
			bill.setBillProcStatus(BILL_STATUS);
			bill.setSysOrgCode(scanIo.getOrgCode());
			bill.setIsPda(1);
			bill.setSupplierId(purchaseOrder.getSupplierId());
			
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(billNo);
			billEntry.setMid(bill.getId());
			billEntry.setBatchNo(billNo + "-10");
			billEntry.setQty(checkNumber);
			billEntry.setSourceType(bill.getSourceType());
			billEntry.setSourceEntryNo(stkIoBillEntry.getEntryNo().toString());
			billEntry.setSourceEntryId(stkIoBillEntry.getId());
			if(null != width) {
				billEntry.setWidth(width);
			}
			billEntry.setLength(length);
			billEntry.setUnitId(material.getUnitId());
			billEntry.setWarehouseId(scanIo.getWarehouseId());
			billEntry.setSettleQty(checkNumber);
			billEntry.setEntryNo(1);
			if(cost == null) {
				cost = scan2ndService.computingStorageCosts(purchaseOrder, material, checkNumber);
			}
			billEntry.setCost(cost);
			BigDecimal settlePrice = cost.divide(checkNumber, 2, BigDecimal.ROUND_DOWN);
			billEntry.setSettlePrice(settlePrice);
			billEntry.setSettleAmt(cost);
			billEntry.setSettleQty(checkNumber);
			billEntry.setSupplierId(purchaseOrder.getSupplierId());
//			billEntry.setSettlePrice(materialPrice);
			
			List<StkIoBillEntry> entryList = Lists.newLinkedList();
			entryList.add(billEntry);
			//采购单是否开票
			bill.setIsInvoice(purchaseOrder.getIsInvoice());
			this.ioBillService.saveMain(bill, entryList);
			this.inventoryService.increase(billEntry);//入库完成添加实时库存
			paymentService.createPayable(bill,entryList);//生成应付账单
			logService.insertLog(bill.getId(), date, billEntry.getId(), stockIoType, 0, material, unit.getId(), purchaseOrder.getId(), 1, cost, billEntry.getQty(), scanIo.getProcedureId());
		}
		
		log.info("采购入库完成");
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		result.setMessage("采购入库完成");
		return result;
	}
	
	/**
	 * @Description 产品入库
	 * @param code
	 * @param number
	 * @param operType
	 * @param userId
	 * @param warehouseId
	 * @param userName
	 * @param orgCode
	 * @param result
	 * @return
	 * Create at: 2020-08-22 10:57:48
	 * @author: duanyong
	 * Revision:
	 *    2020-08-22 10:57:48 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> product(ScanIO scanIo, Result<JSONObject> result){
		//传入参数验证
		String warehouseId = scanIo.getWarehouseId();
		if(StringUtils.isBlank(warehouseId)) {
			return result.error500("未传入仓库ID");
		}
		String listStr = scanIo.getList();
		if(StringUtils.isBlank(listStr)) {
			return result.error500("未传入物料编码");
		}
		JSONArray listArray = JSON.parseArray(listStr);
		if(listArray == null || listArray.size() == 0) {
			return result.error500("未传入物料编码");
		}
		List<String> codes = CollUtil.newArrayList();
		for(int i = 0; i < listArray.size(); i++) {
			JSONObject jsonObject = listArray.getJSONObject(i);
			String codeStr = jsonObject.getString("code");
			if(StringUtils.isNotBlank(codeStr)) {
				codes.add(codeStr);
			}
		}
		if(CollUtil.isEmpty(codes)) {
			return result.error500("未传入物料编码");
		}
		//封装物料信息
		List<BasMaterial> materialList = CollUtil.newLinkedList();
		Map<String, BasMaterial> materialMap = CollUtil.newHashMap();
		Map<String, BasMaterial> materialMapKeyId = CollUtil.newHashMap();
		for (String code : codes) {
			Boolean isTrayCode = ScanUtil.isTrayCode(code);
			if(isTrayCode) {
				StkTray tray = this.trayService.lambdaQuery().eq(StkTray::getCode, code).one();
				if(null == tray) {
					return result.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘未找到").toString());
				}
				List<StkTrayDetail> trayDetails = trayDetailService.lambdaQuery().eq(StkTrayDetail::getTrayId, tray.getId()).list();
				if(CollUtil.isEmpty(trayDetails)) {
					return result.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘上没有物料").toString());
				}
				Iterator<StkTrayDetail> iterator = trayDetails.iterator();
				while(iterator.hasNext()) {
					StkTrayDetail detail = iterator.next();
					String materialId = detail.getMaterialId();
					BasMaterial material = this.materialService.getById(materialId);
					if(null != material) {
						materialList.add(material);
						materialMap.put(material.getCode(), material);
						materialMapKeyId.put(material.getId(), material);
					}
				}
			} else {
				BasMaterial material = this.materialService.getMaterialByCode(code);
				if(null == material) {
					material = this.materialTempService.tempToMaterial(code);
					if(null == material) {
						return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
					}
				}
				materialList.add(material);
				materialMap.put(material.getCode(), material);
				materialMapKeyId.put(material.getId(), material);
			}
		}
		if(CollUtil.isEmpty(materialList)) {
			return result.error500("未找到扫码的物料");
		}
		
		//判断不能重复入库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		for (Iterator<BasMaterial> it = materialList.iterator(); it.hasNext(); ) {
			BasMaterial material = it.next();
			//判断不能重复操作
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(material.getCode());
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode()).append("的物料已执行过入库，").append("不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode()).append("的物料已执行过入库，").append("不能重复操作").toString());
				}
			}
		}
		
		Map<String, List<BasMaterialTemp>> materialListMap = Maps.newLinkedHashMap();
		Map<String, ZrkQzOrder> mesMap = Maps.newHashMap();
		for (BasMaterial material : materialList) {
			String code = material.getCode();
			BasMaterialTemp temp = this.materialTempService.getByCode(code);
			if(null == temp) {
				return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
			}
			String procedureId = temp.getProcedureId();
			if(StringUtils.isBlank(procedureId)) {
				return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			ZrkQzOrder mes = this.mesService.getById(procedureId);
			if(null == mes) {
				return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			if(mesMap.get(procedureId) == null) {
				mesMap.put(procedureId, mes);
			}
			List<BasMaterialTemp> list = materialListMap.get(procedureId);
			if(null == list) {
				list = CollUtil.newArrayList();
				materialListMap.put(procedureId, list);
			}
			list.add(temp);
		}
		for(String mesId : materialListMap.keySet()) {
			ZrkQzOrder mes = mesMap.get(mesId);
			if(null == mes) {
				mes = mesService.getById(mesId);
			}
			
			Date date = DateUtils.gettimestamp();
			String billNo = baseApi.getNoByCode("stock_io_bill_no");
			String stockIoType = scanIo.getOperType();
			String userName = scanIo.getUserName();
			StkIoBill bill = new StkIoBill();
			bill.setBillNo(billNo);
			bill.setStockIoType(stockIoType);
			bill.setBillDate(date);
			bill.setIsAuto(1);
			bill.setClerkId(userName);
			bill.setHandlerId(userName);
//			bill.setApproverId(userName);
			bill.setIsApproved(1);
			bill.setCreateBy(userName);
			bill.setCreateTime(date);
			bill.setIsRubric(0);
			bill.setHasRp(0);
			bill.setSourceType(PRODUCTION_SOURCE_TYPE);
			bill.setSourceId(mes.getId());
			bill.setSourceNo(mes.getCode());
			bill.setBillProcStatus(BILL_STATUS_APPROVAL);
			bill.setSysOrgCode(scanIo.getOrgCode());
			bill.setSupplierId(CommonConstant.QY_SUPPLIER_ID);
			bill.setRemark("生产入库(切张)");
			
			List<StkIoBillEntry> entryList = CollUtil.newArrayList();
			List<BasMaterialTemp> tempList = materialListMap.get(mesId);
			int entryNo = 1;
			Map<String, BasMeasureUnit> unitMap = CollUtil.newHashMap();
			for (Iterator<BasMaterialTemp> it = tempList.iterator(); it.hasNext();) {
				BasMaterialTemp temp = it.next();
				BasMaterial material = materialMap.get(temp.getCode());
				//计算平方
				String unitId = material.getUnitId();
				BasMeasureUnit unit = unitMap.get(unitId);
				if(null == unit) {
					unit = this.unitService.getById(unitId);
					unitMap.put(unitId, unit);
				}
				if(null == unit) {
					return result.error500(new StringBuffer("编码为").append(material.getCode()).append("的物料未维护单位").toString());
				}
				BigDecimal square = null;
				BigDecimal tempSquare = temp.getSquare();
//				BigDecimal materialQty = temp.getAmount();
//				String categoryId = material.getCategoryId();//获取分类ID
//				if ("吨".equals(unit.getName())) {
//					square = this.categoryService.getSquare(materialQty, categoryId);
//				} else if("平方".equals(unit.getName())) {
//					square = temp.getAmount();
//				}
				material.setSquare(tempSquare);
				if (!"平方".equals(unit.getName())) {
					BasMeasureUnit squareUnit = this.unitService.getSquareUnit();
					material.setUnitId(squareUnit.getId());
					material.setQuantity(square);
					temp.setUnitId(squareUnit.getId());
					temp.setAmount(tempSquare);
				}
				this.materialService.updateById(material);
				
				StkIoBillEntry billEntry = new StkIoBillEntry();
				billEntry.setMaterialId(material.getId());
				billEntry.setBillNo(billNo);
				billEntry.setMid(bill.getId());
				int intBatchNo = entryNo * 10;
				billEntry.setBatchNo(billNo + "-" + intBatchNo);
				BigDecimal amount = temp.getAmount();
				if(null != amount) {
					billEntry.setQty(amount);
				} else {
					String unitId2 = temp.getUnitId();
					BasMeasureUnit basMeasureUnit = unitMap.get(unitId2);
					if(null == basMeasureUnit) {
						basMeasureUnit = this.unitService.getById(unitId2);
					}
					if("平方".equals(basMeasureUnit.getName())) {
						billEntry.setQty(temp.getSquare());
					}
				}
				billEntry.setUnitId(material.getUnitId());
				billEntry.setWarehouseId(warehouseId);
				billEntry.setSettleQty(temp.getAmount());
				billEntry.setEntryNo(entryNo);
				entryNo++;
				entryList.add(billEntry);
			}
			//计算成本
			entryList = scan2ndService.countCost(entryList, operType, mesId, tempList, materialMap, materialMapKeyId);
			
			this.ioBillService.saveMain(bill, entryList);
			this.ioBillService.updateInventory(bill, entryList);
			//为每个出入库明细添加log记录
			for(Iterator<StkIoBillEntry> it = entryList.iterator(); it.hasNext();) {
				StkIoBillEntry entry = it.next();
				BasMaterial material = materialMapKeyId.get(entry.getMaterialId());
				if(null == material) {
					material = materialService.getById(entry.getMaterialId());
				}
				logService.insertLog(bill.getId(), date, entry.getId(), bill.getStockIoType(), 0, material, material.getUnitId(), mes.getId(), 1, entry.getCost(), entry.getQty(), mes.getId());
			}
			log.info("生产入库(切张)完成" + bill.getBillNo());
		}
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		result.setMessage("操作成功");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("type", operType);
		result.setResult(jsonObject);
		return result;
	}
	
	/**
	 * @Description 半成品复合入库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-09-21 11:48:15
	 * @author: duanyong
	 * Revision:
	 *    2020-09-21 11:48:15 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> hafeInFuhe(ScanIO scanIo, Result<JSONObject> result) {
		// 传入参数验证
		String warehouseId = scanIo.getWarehouseId();
		if (StringUtils.isBlank(warehouseId)) {
			return result.error500("未传入仓库ID");
		}
		String listStr = scanIo.getList();
		if (StringUtils.isBlank(listStr)) {
			return result.error500("未传入物料编码");
		}
		JSONArray listArray = JSON.parseArray(listStr);
		if (listArray == null || listArray.size() == 0) {
			return result.error500("未传入物料编码");
		}
		List<String> codes = CollUtil.newArrayList();
		for (int i = 0; i < listArray.size(); i++) {
			JSONObject jsonObject = listArray.getJSONObject(i);
			String codeStr = jsonObject.getString("code");
			if (StringUtils.isNotBlank(codeStr)) {
				codes.add(codeStr);
			}
		}
		if (CollUtil.isEmpty(codes)) {
			return result.error500("未传入物料编码");
		}
		// 封装物料信息
		List<BasMaterial> materialList = CollUtil.newLinkedList();
		Map<String, BasMaterial> materialMap = CollUtil.newHashMap();
		Map<String, BasMaterial> materialMapKeyId = CollUtil.newHashMap();
		for (String code : codes) {
			Boolean isTrayCode = ScanUtil.isTrayCode(code);
			if (isTrayCode) {
				StkTray tray = this.trayService.lambdaQuery().eq(StkTray::getCode, code).one();
				if (null == tray) {
					return result
							.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘未找到").toString());
				}
				List<StkTrayDetail> trayDetails = trayDetailService.lambdaQuery()
						.eq(StkTrayDetail::getTrayId, tray.getId()).list();
				if (CollUtil.isEmpty(trayDetails)) {
					return result
							.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘上没有物料").toString());
				}
				Iterator<StkTrayDetail> iterator = trayDetails.iterator();
				while (iterator.hasNext()) {
					StkTrayDetail detail = iterator.next();
					String materialId = detail.getMaterialId();
					BasMaterial material = this.materialService.getById(materialId);
					if (null != material) {
						materialList.add(material);
						materialMap.put(material.getCode(), material);
						materialMapKeyId.put(material.getId(), material);
					}
				}
			} else {
				BasMaterial material = this.materialService.getMaterialByCode(code);
				if (null == material) {
					material = this.materialTempService.tempToMaterial(code);
					if (null == material) {
						return result
								.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
					}
				}
				materialList.add(material);
				materialMap.put(material.getCode(), material);
				materialMapKeyId.put(material.getId(), material);
			}
		}
		if (CollUtil.isEmpty(materialList)) {
			return result.error500("未找到扫码的物料");
		}

		// 判断不能重复入库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		for (Iterator<BasMaterial> it = materialList.iterator(); it.hasNext();) {
			BasMaterial material = it.next();
			// 判断不能重复操作
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(material.getCode());
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode())
							.append("的物料已执行过入库，").append("不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode())
							.append("的物料已执行过入库，").append("不能重复操作").toString());
				}
			}
		}

		Map<String, List<BasMaterialTemp>> materialListMap = Maps.newLinkedHashMap();
		Map<String, ZrkQzOrder> mesMap = Maps.newHashMap();
		for (BasMaterial material : materialList) {
			String code = material.getCode();
			BasMaterialTemp temp = this.materialTempService.getByCode(code);
			if (null == temp) {
				return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
			}
			String procedureId = temp.getProcedureId();
			if (StringUtils.isBlank(procedureId)) {
				return result
						.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			ZrkQzOrder mes = this.mesService.getById(procedureId);
			if (null == mes) {
				return result
						.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			if (mesMap.get(procedureId) == null) {
				mesMap.put(procedureId, mes);
			}
			List<BasMaterialTemp> list = materialListMap.get(procedureId);
			if (null == list) {
				list = CollUtil.newArrayList();
				materialListMap.put(procedureId, list);
			}
			list.add(temp);
		}
		for (String mesId : materialListMap.keySet()) {
			ZrkQzOrder mes = mesMap.get(mesId);
			if (null == mes) {
				mes = mesService.getById(mesId);
			}
			String prodId = mes.getId();
			if(StringUtils.isNotBlank(mes.getParentId())) {
				prodId = mes.getParentId();
			}
			ZrkQzOrder preMes = this.mesService.getById(prodId);

			Date date = DateUtils.gettimestamp();
			String billNo = baseApi.getNoByCode("stock_io_bill_no");
			String stockIoType = scanIo.getOperType();
			String userName = scanIo.getUserName();
			StkIoBill bill = new StkIoBill();
			bill.setBillNo(billNo);
			bill.setStockIoType(stockIoType);
			bill.setBillDate(date);
			bill.setIsAuto(1);
			bill.setClerkId(userName);
			bill.setHandlerId(userName);
//					bill.setApproverId(userName);
			bill.setIsApproved(1);
			bill.setCreateBy(userName);
			bill.setCreateTime(date);
			bill.setIsRubric(0);
			bill.setHasRp(0);
			bill.setSourceType(PRODUCTION_SOURCE_TYPE);
			bill.setSourceId(preMes.getId());
			bill.setSourceNo(preMes.getCode());
			bill.setBillProcStatus(BILL_STATUS_APPROVAL);
			bill.setSysOrgCode(scanIo.getOrgCode());
			bill.setSupplierId(CommonConstant.QY_SUPPLIER_ID);
			bill.setRemark("生产入库(复合)");

			List<StkIoBillEntry> entryList = CollUtil.newArrayList();
			List<BasMaterialTemp> tempList = materialListMap.get(mesId);
			int entryNo = 1;
			Map<String, BasMeasureUnit> unitMap = CollUtil.newHashMap();
			for (Iterator<BasMaterialTemp> it = tempList.iterator(); it.hasNext();) {
				BasMaterialTemp temp = it.next();
				BasMaterial material = materialMap.get(temp.getCode());
				// 计算平方
				String unitId = material.getUnitId();
				BasMeasureUnit unit = unitMap.get(unitId);
				if (null == unit) {
					unit = this.unitService.getById(unitId);
					unitMap.put(unitId, unit);
				}
				BigDecimal square = null;
				BigDecimal materialQty = temp.getAmount();
				String categoryId = material.getCategoryId();// 获取分类ID
				if(null == unit) {
					return result.error500(new StringBuffer("编码为").append(material.getCode()).append("的物料未维护单位。").toString());
				}
				if ("吨".equals(unit.getName())) {
					square = this.categoryService.getSquare(materialQty, categoryId);
				} else if ("平方".equals(unit.getName())) {
					square = temp.getAmount();
				}
				material.setSquare(square);
				this.materialService.updateById(material);

				StkIoBillEntry billEntry = new StkIoBillEntry();
				billEntry.setMaterialId(material.getId());
				billEntry.setBillNo(billNo);
				billEntry.setMid(bill.getId());
				int intBatchNo = entryNo * 10;
				billEntry.setBatchNo(billNo + "-" + intBatchNo);
				BigDecimal amount = temp.getAmount();
				if(null != amount) {
					billEntry.setQty(amount);
				} else {
					String unitId2 = temp.getUnitId();
					BasMeasureUnit basMeasureUnit = unitMap.get(unitId2);
					if(null == basMeasureUnit) {
						basMeasureUnit = this.unitService.getById(unitId2);
					}
					if("平方".equals(basMeasureUnit.getName())) {
						billEntry.setQty(temp.getSquare());
					}
				}
				billEntry.setUnitId(material.getUnitId());
				billEntry.setWarehouseId(warehouseId);
				billEntry.setSettleQty(temp.getAmount());
				billEntry.setEntryNo(entryNo);
				entryNo++;
				entryList.add(billEntry);
			}
			// 计算成本
			entryList = scan2ndService.countCost(entryList, operType, mesId, tempList, materialMap, materialMapKeyId);

			this.ioBillService.saveMain(bill, entryList);
			this.ioBillService.updateInventory(bill, entryList);
			// 为每个出入库明细添加log记录
			for (Iterator<StkIoBillEntry> it = entryList.iterator(); it.hasNext();) {
				StkIoBillEntry entry = it.next();
				BasMaterial material = materialMapKeyId.get(entry.getMaterialId());
				if (null == material) {
					material = materialService.getById(entry.getMaterialId());
				}
				logService.insertLog(bill.getId(), date, entry.getId(), bill.getStockIoType(), 0, material,
						material.getUnitId(), mes.getId(), 1, entry.getCost(), entry.getQty(), preMes.getId());
			}
			log.info("生产入库(复合)完成" + bill.getBillNo());
		}
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		result.setMessage("操作成功");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("type", operType);
		result.setResult(jsonObject);
		return result;
	}
	
	/**
	 * @Description 半成品分切入库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-09-21 11:48:34
	 * @author: duanyong
	 * Revision:
	 *    2020-09-21 11:48:34 - first revision by duanyong
	 *        
	 */
	private Result<JSONObject> hafeInFenqie(ScanIO scanIo, Result<JSONObject> result) {
		// 传入参数验证
		String warehouseId = scanIo.getWarehouseId();
		if (StringUtils.isBlank(warehouseId)) {
			return result.error500("未传入仓库ID");
		}
		String listStr = scanIo.getList();
		if (StringUtils.isBlank(listStr)) {
			return result.error500("未传入物料编码");
		}
		JSONArray listArray = JSON.parseArray(listStr);
		if (listArray == null || listArray.size() == 0) {
			return result.error500("未传入物料编码");
		}
		List<String> codes = CollUtil.newArrayList();
		for (int i = 0; i < listArray.size(); i++) {
			JSONObject jsonObject = listArray.getJSONObject(i);
			String codeStr = jsonObject.getString("code");
			if (StringUtils.isNotBlank(codeStr)) {
				codes.add(codeStr);
			}
		}
		if (CollUtil.isEmpty(codes)) {
			return result.error500("未传入物料编码");
		}
		List<BasMeasureUnit> unitList = this.unitService.list();
		Map<String, BasMeasureUnit> unitMap = Maps.newHashMap();
		for(BasMeasureUnit basUnit : unitList) {
			unitMap.put(basUnit.getId(), basUnit);
		}
		// 封装物料信息
		List<BasMaterial> materialList = CollUtil.newLinkedList();
		Map<String, BasMaterial> materialMap = CollUtil.newHashMap();
		Map<String, BasMaterial> materialMapKeyId = CollUtil.newHashMap();
		for (String code : codes) {
			Boolean isTrayCode = ScanUtil.isTrayCode(code);
			if (isTrayCode) {
				StkTray tray = this.trayService.lambdaQuery().eq(StkTray::getCode, code).one();
				if (null == tray) {
					return result
							.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘未找到").toString());
				}
				List<StkTrayDetail> trayDetails = trayDetailService.lambdaQuery()
						.eq(StkTrayDetail::getTrayId, tray.getId()).list();
				if (CollUtil.isEmpty(trayDetails)) {
					return result
							.error500(new StringBuffer("").append("托盘码").append(code).append("对应的托盘上没有物料").toString());
				}
				Iterator<StkTrayDetail> iterator = trayDetails.iterator();
				while (iterator.hasNext()) {
					StkTrayDetail detail = iterator.next();
					String materialId = detail.getMaterialId();
					BasMaterial material = this.materialService.getById(materialId);
					if (null != material) {
						materialList.add(material);
						materialMap.put(material.getCode(), material);
						materialMapKeyId.put(material.getId(), material);
					}
				}
			} else {
				BasMaterial material = this.materialService.getMaterialByCode(code);
				if (null == material) {
					material = this.materialTempService.tempToMaterial(code);
					if (null == material) {
						return result
								.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
					}
				}
				materialList.add(material);
				materialMap.put(material.getCode(), material);
				materialMapKeyId.put(material.getId(), material);
			}
		}
		if (CollUtil.isEmpty(materialList)) {
			return result.error500("未找到扫码的物料");
		}

		// 判断不能重复入库
		String operType = scanIo.getOperType();
		boolean inFlag = false;
		boolean outFlag = false;
		for (String string : inTypes) {
			if (operType.equals(string)) {
				inFlag = true;
				break;
			}
		}
		for (String string : outTypes) {
			if (operType.equals(string)) {
				outFlag = true;
				break;
			}
		}
		for (Iterator<BasMaterial> it = materialList.iterator(); it.hasNext();) {
			BasMaterial material = it.next();
			// 判断不能重复操作
			StkIoBill latestBill = this.billMapper.selectByMaterialCode(material.getCode());
			if (null != latestBill) {
				String type = latestBill.getStockIoType();
				if (operType.equals(type)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode())
							.append("的物料已执行过入库，").append("不能重复操作").toString());
				}
				boolean inF = false;
				boolean outF = false;
				for (String string : inTypes) {
					if (type.equals(string)) {
						inF = true;
						break;
					}
				}
				for (String string : outTypes) {
					if (type.equals(string)) {
						outF = true;
						break;
					}
				}
				if ((inFlag && inF) || (outFlag && outF)) {
					return result.error500(new StringBuffer("").append("编码为").append(material.getCode())
							.append("的物料已执行过入库，").append("不能重复操作").toString());
				}
			}
		}

		Map<String, List<BasMaterialTemp>> materialListMap = Maps.newLinkedHashMap();
		Map<String, ZrkQzOrder> mesMap = Maps.newHashMap();
		for (BasMaterial material : materialList) {
			String code = material.getCode();
			BasMaterialTemp temp = this.materialTempService.getByCode(code);
			if (null == temp) {
				return result.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到").toString());
			}
			String procedureId = temp.getProcedureId();
			if (StringUtils.isBlank(procedureId)) {
				return result
						.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			ZrkQzOrder mes = this.mesService.getById(procedureId);
			if (null == mes) {
				return result
						.error500(new StringBuffer("").append("编码为").append(code).append("的物料未找到对应的MES单").toString());
			}
			if (mesMap.get(procedureId) == null) {
				mesMap.put(procedureId, mes);
			}
			List<BasMaterialTemp> list = materialListMap.get(procedureId);
			if (null == list) {
				list = CollUtil.newArrayList();
				materialListMap.put(procedureId, list);
			}
			list.add(temp);
		}
		for (String mesId : materialListMap.keySet()) {
			ZrkQzOrder mes = mesMap.get(mesId);
			if (null == mes) {
				mes = mesService.getById(mesId);
			}

			Date date = DateUtils.gettimestamp();
			String billNo = baseApi.getNoByCode("stock_io_bill_no");
			String stockIoType = scanIo.getOperType();
			String userName = scanIo.getUserName();
			StkIoBill bill = new StkIoBill();
			bill.setBillNo(billNo);
			bill.setStockIoType(stockIoType);
			bill.setBillDate(date);
			bill.setIsAuto(1);
			bill.setClerkId(userName);
			bill.setHandlerId(userName);
//					bill.setApproverId(userName);
			bill.setIsApproved(1);
			bill.setCreateBy(userName);
			bill.setCreateTime(date);
			bill.setIsRubric(0);
			bill.setHasRp(0);
			bill.setSourceType(PRODUCTION_SOURCE_TYPE);
			bill.setSourceId(mes.getId());
			bill.setSourceNo(mes.getCode());
			bill.setBillProcStatus(BILL_STATUS_APPROVAL);
			bill.setSysOrgCode(scanIo.getOrgCode());
			bill.setSupplierId(CommonConstant.QY_SUPPLIER_ID);
			bill.setRemark("生产入库(分切)");

			List<StkIoBillEntry> entryList = CollUtil.newArrayList();
			List<BasMaterialTemp> tempList = materialListMap.get(mesId);
			int entryNo = 1;
			for (Iterator<BasMaterialTemp> it = tempList.iterator(); it.hasNext();) {
				BasMaterialTemp temp = it.next();
				BasMaterial material = materialMap.get(temp.getCode());
				// 计算平方
				String unitId = material.getUnitId();
				BasMeasureUnit unit = unitMap.get(unitId);
				if (null == unit) {
					unit = this.unitService.getById(unitId);
					unitMap.put(unitId, unit);
				}
				BigDecimal square = null;
				BigDecimal materialQty = temp.getAmount();
				String categoryId = material.getCategoryId();// 获取分类ID
				if(null == unit) {
					return result.error500(new StringBuffer("编码为").append(material.getCode()).append("的物料未维护单位").toString());
				}
				if ("吨".equals(unit.getName())) {
					square = this.categoryService.getSquare(materialQty, categoryId);
				} else if ("平方".equals(unit.getName())) {
					square = temp.getAmount();
				}

				StkIoBillEntry billEntry = new StkIoBillEntry();
				billEntry.setMaterialId(material.getId());
				billEntry.setBillNo(billNo);
				billEntry.setMid(bill.getId());
				int intBatchNo = entryNo * 10;
				billEntry.setBatchNo(billNo + "-" + intBatchNo);
				BigDecimal amount = temp.getAmount();
				BigDecimal temSquare = temp.getSquare();
				
				String unitId2 = temp.getUnitId();
				BasMeasureUnit basMeasureUnit = unitMap.get(unitId2);
				if(null != amount) {
					billEntry.setQty(amount);
				} else {
					if(null == basMeasureUnit) {
						basMeasureUnit = this.unitService.getById(unitId2);
					}
					if("平方".equals(basMeasureUnit.getName())) {
						billEntry.setQty(temp.getSquare());
					}
				}
				if(null == billEntry.getQty() && null != temSquare) {
					billEntry.setQty(temSquare);
					BasMeasureUnit squareUnit = this.unitService.getSquareUnit();
					billEntry.setUnitId(squareUnit.getId());
					material.setUnitId(squareUnit.getId());
					temp.setUnitId(squareUnit.getId());
					this.materialTempService.updateById(temp);
				}
				material.setSquare(square);
				this.materialService.updateById(material);
				
				billEntry.setUnitId(material.getUnitId());
				billEntry.setWarehouseId(warehouseId);
				billEntry.setSettleQty(temp.getAmount());
				billEntry.setEntryNo(entryNo);
				entryNo++;

//						StkIoMaterialLog log = StkIoMaterialLog.builder()
//								.materialId(material.getId())
//								.ioType(scanIo.getOperType())
//								.amount(temp.getAmount())
//								.square(square)
//								.width(material.getWidth())
//								.length(material.getLength())
//								.procedureId(mes.getId())
//								.build();
//						BigDecimal cost = scan2ndService.getMaterialCost(log);
//						billEntry.setCost(cost);
				entryList.add(billEntry);
			}
			// 计算成本
			entryList = scan2ndService.countCost(entryList, operType, mesId, tempList, materialMap, materialMapKeyId);

			this.ioBillService.saveMain(bill, entryList);
			this.ioBillService.updateInventory(bill, entryList);
			// 为每个出入库明细添加log记录
			for (Iterator<StkIoBillEntry> it = entryList.iterator(); it.hasNext();) {
				StkIoBillEntry entry = it.next();
				BasMaterial material = materialMapKeyId.get(entry.getMaterialId());
				if (null == material) {
					material = materialService.getById(entry.getMaterialId());
				}
				logService.insertLog(bill.getId(), date, entry.getId(), bill.getStockIoType(), 0, material,
						material.getUnitId(), mes.getId(), 1, entry.getCost(), entry.getQty(), mes.getId());
			}
			log.info("生产入库(分切)完成" + bill.getBillNo());
		}
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		result.setMessage("操作成功");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("type", operType);
		result.setResult(jsonObject);
		return result;
	}
	
	/**
	 * @Description 销售出库
	 * @param scanIo
	 * @param result
	 * @return
	 * Create at: 2020-08-22 17:28:05
	 * @author: duanyong
	 * Revision:
	 *    2020-08-22 17:28:05 - first revision by duanyong
	 *        
	 */
	@Transactional
	private Result<JSONObject> saleOut(ScanIO scanIo, Result<JSONObject> result){
		//根据物料编码查询物料
		String listStr = scanIo.getList();
		List<String> codes = Lists.newArrayList();
		JSONArray array = JSONArray.parseArray(listStr);
		for (int i = 0; i < array.size(); i++) {
			JSONObject jsonObject = array.getJSONObject(i);
			codes.add(jsonObject.getString("code"));
		}
		String warehouseId = scanIo.getWarehouseId();
		if(!warehouseService.checkWarehouseSaleOut(warehouseId)) {
			return result.error500("所选仓库不为成品库。");
		}
		String customerId = scanIo.getCustomerId();
		if(StringUtils.isBlank(customerId)) {
			return result.error500("请选择客户。");
		}
		int orderCount = zrkShopOrderService.lambdaQuery().eq(ZrkShoporder::getCustomerId, customerId).count();
		if(orderCount == 0) {
			return result.error500("该客户没有订单。");
		}
		List<ZrkOrderProduct> productList = this.orderProductService.getByCustomerId2(customerId);
		if(CollUtil.isEmpty(productList)) {
			return result.error500("该客户没有订单需要出库。");
		}
		
		String isFinal = scanIo.getIsFinal();
		Map<String, BasMaterial> materialMap = Maps.newHashMap();
		Map<String, BasMaterial> materialMapKeyId = Maps.newHashMap();
		List<StkTray> trayList = Lists.newArrayList();
		List<BasMaterial> materialList = Lists.newArrayList();
		for (Iterator<String> iterator = codes.iterator(); iterator.hasNext();) {
			String code = iterator.next();
			Boolean isTray = ScanUtil.isTrayCode(code);
			if(isTray) {
				StkTray tray = this.trayService.lambdaQuery().eq(StkTray::getCode, code).one();
				if(null == tray) {
					return result.error500(new StringBuffer("托盘码").append(code).append("对应的托盘未找到").toString());
				}
				String trayCustomerId = tray.getCustomerId();
				if(!customerId.equals(trayCustomerId)) {
					return result.error500(new StringBuffer("托盘码为").append(code).append("的托盘客户与要出库的客户不符").toString());
				}
				List<StkTrayDetail> trayDetails = trayDetailService.lambdaQuery().eq(StkTrayDetail::getTrayId, tray.getId()).list();
				if(CollUtil.isEmpty(trayDetails)) {
					return result.error500(new StringBuffer("托盘码").append(code).append("对应的托盘上没有物料").toString());
				}
				for(Iterator<StkTrayDetail> it = trayDetails.iterator(); it.hasNext();) {
					StkTrayDetail detail = it.next();
					String materialId = detail.getMaterialId();
					BasMaterial material = this.materialService.getById(materialId);
					if(null != material) {
						materialList.add(material);
						materialMap.put(material.getCode(), material);
						materialMapKeyId.put(material.getId(), material);
					}
				}
				trayList.add(tray);
			} else {
				BasMaterial material = this.materialService.getMaterialByCode(code);
				if(material == null) {
					return result.error500(new StringBuffer("物料码为").append(code).append("的物料未找到").toString());
				}
				String materialCustomerId = material.getCustomerId();
				if(null == materialCustomerId || !customerId.equals(materialCustomerId)) {
					return result.error500(new StringBuffer("物料码为").append(code).append("的物料客户与要出库的客户不符").toString());
				}
				if(null != material) {
					materialList.add(material);
				}
			}
		}
		
		List<String> materialIds = Lists.newArrayList(); 
		List<String> materialCodes = Lists.newArrayList();
		for (BasMaterial basMaterial : materialList) {
			materialIds.add(basMaterial.getId());
			materialCodes.add(basMaterial.getCode());
		}
		if(CollUtil.isEmpty(materialIds)) {
			return result.error500("未找到相关的物料信息。");
		}
		List<StkInventory> inventorys = inventoryService.selectByMaterials(materialIds);
		if(null == inventorys || inventorys.size() == 0) {
//			return result.error500("产品信息与实时库存不符。");
		}
		if(materialList.size() != inventorys.size()) {
//			return result.error500("扫描的产品没有库存记录。");
		}
		for (StkInventory inventory : inventorys) {
			if(!warehouseId.equals(inventory.getWarehouseId())) {
				return result.error500("产品所在仓库与选中的仓库不符。");
			}
			if(inventory.getQty().compareTo(BigDecimal.ZERO) <= 0) {
				return result.error500("产品库存不足。");
			}
		}
		List<BasMaterialTemp> tempList = this.materialTempService.getByCodes(materialCodes);
		HashSet<String> tempProcedureIdList = Sets.newHashSet();
		Map<String, BasMaterialTemp> tempMap = Maps.newHashMap();//存储物料Temp表信息
		for(BasMaterialTemp temp : tempList) {
			tempMap.put(temp.getCode(), temp);
			String procedureId = temp.getProcedureId();
			if(StringUtils.isNotBlank(procedureId)) {
				tempProcedureIdList.add(procedureId);
			}
		}
		
		//入库物料和销售单的关系
		Map<ZrkOrderProduct, List<BasMaterial>> orderProductMap = Maps.newHashMap();
		Map<String, List<ZrkOrderProduct>> categoryProductMap = Maps.newHashMap();
		for(ZrkOrderProduct product : productList) {
			String categoryId = product.getMaterialId();
			List<ZrkOrderProduct> list = categoryProductMap.get(categoryId);
			if(list == null) {
				list = CollUtil.newArrayList(product);
				categoryProductMap.put(categoryId, list);
			} else {
				list.add(product);
			}
		}
		//查询工序
		List<ZzDeviceType> deviceTypeList = deviceTypeService.list();
		Map<String, ZzDeviceType> deviceTypeMap = Maps.newHashMap();
		if(CollUtil.isNotEmpty(deviceTypeList)) {
			for (ZzDeviceType zzDeviceType : deviceTypeList) {
				deviceTypeMap.put(zzDeviceType.getId(), zzDeviceType);
			}
		}
		//查询MES单据
		List<ZrkQzOrder> mesList = this.mesService.listByIds(tempProcedureIdList);
		Map<String, ZrkQzOrder> mesMap = Maps.newHashMap();
		if(CollUtil.isNotEmpty(mesList)) {
			for (ZrkQzOrder mes : mesList) {
				mesMap.put(mes.getId(), mes);
			}
		}
		
		BigDecimal decimal100 = new BigDecimal("100");
		String outCompletStatus = "2";
		HashSet<String> orderIdSet = Sets.newHashSet();//存储订单ID的集合，用于打印单据
		Map<String, ZrkOrderProduct> materialProductMap = Maps.newHashMap();//存储物料与订单详情的对应关系
		for(BasMaterial material : materialList) {
			String categoryId = material.getCategoryId();
			BigDecimal width = material.getWidth();
			BigDecimal length = material.getLength();
			List<ZrkOrderProduct> list = Lists.newArrayList();
			List<ZrkOrderProduct> list1 = categoryProductMap.get(categoryId);
			if(CollUtil.isNotEmpty(list1)) {
				list.addAll(list1);
			}
			BasMaterialTemp temp = tempMap.get(material.getCode());
			String procedureId = temp.getProcedureId();
			ZrkQzOrder mes = this.mesService.getById(procedureId);
			String mesProcessId = mes.getProcessId();
			BigDecimal quantity = material.getViceQuantity();//物料副数量
			ZrkOrderProduct materialProduct = null;
			for(ZrkOrderProduct product : list) {
				BigDecimal productCount = product.getProductCount();
				String outStatus = product.getOutStatus();
				if(outCompletStatus.equals(outStatus)) {
					continue;
				}
				BigDecimal outCount = product.getOutCount() == null ? BigDecimal.ZERO : product.getOutCount();
				String processId = product.getProcessId();
				ZzDeviceType process = deviceTypeMap.get(processId);
				String tpyeName = process.getDeviceTpyeName();
				List<BasMaterial> productMaterials = orderProductMap.get(product);
				if(null == productMaterials) {
					productMaterials = Lists.newArrayList();
					orderProductMap.put(product, productMaterials);
				}
				String productSpecs = product.getProductSpecs();
				if(StringUtils.isBlank(productSpecs)) {
					continue;
				}
				String[] strs = StringUtils.split(productSpecs, "*");
				if(strs.length != 2) {
					continue;
				}
				BigDecimal productWidth = new BigDecimal(strs[0]);
				if(StringUtils.contains(tpyeName, "切张")) {
					BigDecimal productLength = new BigDecimal(strs[1]);
					productLength = productLength.multiply(decimal100);
					material.getViceQuantity();
					if(((productWidth.compareTo(width) == 0 
							&& productLength.compareTo(length) == 0) 
							|| (productLength.compareTo(width) == 0 
									&& productWidth.compareTo(length) == 0) )) {
						BigDecimal surplusCount = productCount.subtract(outCount);//剩余的张数
						if(surplusCount.compareTo(quantity) >= 0) {
							outCount = outCount.add(quantity);
						}
						product.setOutCount(outCount);
						if(outCount.compareTo(productCount) >= 0) {
							product.setOutStatus(outCompletStatus);
						} else {
							product.setOutStatus("1");
						}
						materialProduct = product;
						if(!orderIdSet.contains(product.getOrderId())) {
							orderIdSet.add(product.getOrderId());
						}
					}
				} else {
					if(material.getViceQuantity().compareTo(BigDecimal.TEN) < 0 && productWidth.compareTo(width) == 0) {
						outCount = outCount.add(material.getViceQuantity());
						if(outCount.compareTo(productCount) >= 0) {
							product.setOutStatus(outCompletStatus);
						} else {
							product.setOutStatus("1");
						}
						product.setOutCount(outCount);
						materialProduct = product;
						if(!orderIdSet.contains(product.getOrderId())) {
							orderIdSet.add(product.getOrderId());
						}
					}
				}
				if(materialProduct != null) {
					materialProductMap.put(material.getId(), materialProduct);
					break;
				}
			}
			if(null != materialProduct) {
				continue;
			}
			
			return result.error500(StrUtil.builder("物料码为", material.getCode(), "的物料不在客户的订单中。").toString());
		}
		
//		String orderNum = scanIo.getOrderNum();
//		ZrkShoporder order = zrkShopOrderService.getById(orderNum);
//		String resultStr = scan2ndService.checkSaleOutOrder(order, materialList, scanIo);
//		if("noproduct".equals(resultStr)) {
//			return result.error500("扫描的产品不在销售订单中。");
//		}
//		if("noin".equals(resultStr)) {
//			return result.error500("扫码的商品没有入库记录。");
//		}
//		if("less".equals(resultStr)) {
//			return result.error500("出库的商品不够。");
//		}
//		if("more".equals(resultStr)) {
//			return result.error500("出库的商品过多。");
//		}
//		Map<String, BigDecimal> productPriceMap = Maps.newHashMap();
//		for (ZrkOrderProduct zrkOrderProduct : productList) {
//			String materialId = zrkOrderProduct.getMaterialId();
//			BigDecimal price = zrkOrderProduct.getUnitPrice();
//			productPriceMap.put(materialId, price);
//		}
		
//		String orderCode = order.getOrderCode();
//		List<StkIoBill> saleOutBillList = this.billService.getSaleOutBillBySourceCode(orderCode);
//		StkIoBill existBill = null;
//		Map<String, StkIoBillEntry> entryMap = Maps.newHashMap();
//		if(CollUtil.isNotEmpty(saleOutBillList)) {
//			for (StkIoBill saleOutBill : saleOutBillList) {
//				String status = StringUtils.rightPad(saleOutBill.getBillProcStatus(), 3, "0");
//				if(Integer.parseInt(status) < 200) {
//					existBill = saleOutBill;
//				}
//				String billId = saleOutBill.getId();
//				List<StkIoBillEntry> entrys = this.billEntryService.selectByMainId(billId);
//				if(null == entrys) {
//					continue;
//				}
//				Iterator<StkIoBillEntry> it = entrys.iterator();
//				while(it.hasNext()) {
//					StkIoBillEntry entry = it.next();
//					entryMap.put(entry.getMaterialId(), entry);
//				}
//			}
//		}
//		List<BasMaterial> billMaterials = Lists.newArrayList();
//		for (BasMaterial basMaterial : materialList) {
//			if(entryMap.get(basMaterial.getId()) == null) {
//				billMaterials.add(basMaterial);
//			}
//		}
//		if(billMaterials.size() == 0) {
//			return result.error500("扫码的物料已经在销售出库单中。");
//		}
		
		//封装销售出库单
		Date date = DateUtils.gettimestamp();
		String billNo = baseApi.getNoByCode("stock_io_bill_no");
		String stockIoType = scanIo.getOperType();
		String userName = scanIo.getUserName();
		StkIoBill bill = new StkIoBill();
		bill.setBillNo(billNo);
		bill.setStockIoType(stockIoType);
		bill.setBillDate(date);
		bill.setIsAuto(1);
		bill.setClerkId(userName);
		bill.setHandlerId(userName);
//		bill.setApproverId(userName);
		bill.setIsApproved(0);
		bill.setCreateBy(userName);
		bill.setCreateTime(date);
		bill.setIsRubric(0);
		bill.setIsPda(1);
		bill.setIsClosed(0);
		bill.setHasRp(1);
		bill.setBillProcStatus(BILL_STATUS);
		bill.setSysOrgCode(scanIo.getOrgCode());
		bill.setSourceType(SALE_SOURCE_TYPE);
//		bill.setSourceId(order.getId());
//		bill.setSourceNo(order.getOrderNo());
		bill.setRemark("销售扫码出库");
		bill.setCustomerId(customerId);
		List<StkIoBillEntry> entryList = Lists.newArrayList();
		int entryNum = 1;
		for (BasMaterial material : materialList) {
			//获得该物料最近的入库记录
			List<StkIoBillEntry> perEntryList = billEntryService.selectByMaterial(material.getId());
			if(null == perEntryList || perEntryList.size() == 0) {
				return result.error500("扫码的商品没有入库记录。");
			}
			StkIoBillEntry lastEntry = null;
			for (StkIoBillEntry stkIoBillEntry : perEntryList) {
				StkIoBill mBill = this.billService.getById(stkIoBillEntry.getMid());
				if(inTypes.contains(mBill.getStockIoType())) {
					lastEntry = stkIoBillEntry;
					break;
				}
			}
			if(lastEntry == null) {
				return result.error500("扫码的商品没有入库记录。");
			}
			StkIoBillEntry billEntry = new StkIoBillEntry();
			billEntry.setMaterialId(material.getId());
			billEntry.setBillNo(billNo);
			billEntry.setMid(bill.getId());
			billEntry.setBatchNo(lastEntry.getBatchNo());
			billEntry.setQty(lastEntry.getQty());
			billEntry.setUnitId(material.getUnitId());
			billEntry.setWarehouseId(scanIo.getWarehouseId());
			billEntry.setSettleQty(lastEntry.getQty());
			billEntry.setEntryNo(entryNum);
			billEntry.setSourceEntryId(lastEntry.getId());
			billEntry.setLength(material.getLength());
			billEntry.setWidth(material.getWidth());
			ZrkOrderProduct zrkOrderProduct = materialProductMap.get(material.getId());
			BigDecimal unitPrice = zrkOrderProduct.getUnitPrice();
//			if(unitPrice == null) {
//				List<String> categoryIds = Lists.newArrayList();
//				categoryIds.add(categoryId);
//				categoryIds = this.getParentCategory(categoryIds, categoryId);
//				for (String cId : categoryIds) {
//					unitPrice = productPriceMap.get(cId);
//					if(null != unitPrice) {
//						break;
//					}
//				}
//			}
			if(unitPrice == null) {
				return result.error500("销售单单价不正确");
			}
			BigDecimal cost = unitPrice.multiply(billEntry.getQty());
			cost = cost.setScale(2, BigDecimal.ROUND_HALF_UP);
			billEntry.setCost(lastEntry.getCost());
			billEntry.setSettlePrice(unitPrice);//单价
			billEntry.setSettleAmt(cost);//结算金额
			if(null != lastEntry.getEntryNo()) {
				billEntry.setSourceEntryNo(lastEntry.getEntryNo().toString());
			}
			entryList.add(billEntry);
			entryNum ++;
		}
		this.ioBillService.saveMain(bill, entryList);
		//封装出货单
		ZrkDeliver deliver = new ZrkDeliver();
		String code = baseApi.getNoByCode("sale_shipment_bill_no");
		deliver.setDeliverCode(code);
		deliver.setCreateBy(userName);
		deliver.setBillNo(bill.getBillNo());
		deliver.setCreateTime(date);
		deliver.setSaleOrderId(bill.getSourceId());
		deliver.setCustomerId(bill.getCustomerId());
		List<ZrkDeliverEntry> deliverEntryList = Lists.newArrayList();
		for (StkIoBillEntry billEntry : entryList) {
			ZrkDeliverEntry entry = new ZrkDeliverEntry();
			deliverEntryList.add(entry);
			entry.setCreateBy(userName);
			entry.setCreateTime(date);
			String materialId = billEntry.getMaterialId();
			
			entry.setMaterialId(materialId);
			entry.setWidth(billEntry.getWidth());
			entry.setLength(billEntry.getLength());
			BasMaterial material = materialMapKeyId.get(materialId);
			if(null != material) {
				entry.setSquare(material.getSquare());
			}
			entry.setMaterialCount(billEntry.getQty());
			entry.setUnitId(billEntry.getUnitId());
		}
		this.deliverService.saveMain(deliver, deliverEntryList);
		if(CollUtil.isNotEmpty(trayList)) {
			for (StkTray stkTray : trayList) {
				stkTray.setDeliverCode(code);
				stkTray.setDeliverId(deliver.getId());
				stkTray.setBillId(bill.getId());
				stkTray.setBillNo(bill.getBillNo());
			}
			trayService.updateBatchById(trayList);
		}
		//修改销售订单状态
		for(List<ZrkOrderProduct> list : categoryProductMap.values()) {
			if(CollUtil.isEmpty(list)) {
				continue;
			}
			for (ZrkOrderProduct orderProduct : list) {
				this.orderProductService.updateById(orderProduct);
				if(orderProduct.getOutStatus().equals("2")) {
					String orderId = orderProduct.getOrderId();
					ZrkShoporder shoporder = this.zrkShopOrderService.getById(orderId);
					if(null != shoporder) {
						shoporder.setOrderStatus("3");
						this.zrkShopOrderService.updateById(shoporder);
					}
				}
			}
		}
		
		//关联表信息添加
		List<ZrkOrderProductMaterialLk> lkList = Lists.newArrayList();
		for(Map.Entry<String, ZrkOrderProduct> entry : materialProductMap.entrySet()) {
			String materialId = entry.getKey();
			ZrkOrderProduct product = entry.getValue();
			ZrkOrderProductMaterialLk lk = new ZrkOrderProductMaterialLk();
			lk.setMaterialId(materialId);
			lk.setProductId(product.getId());
			lk.setOrderId(product.getOrderId());
			lkList.add(lk);
		}
		this.productMaterialLkService.saveBatch(lkList);
		
		//如果是最后一次出库
		if(isFinal != null && isFinal.equals("是")) {
			
		}
		//审批通过
		this.billService.approve(bill.getId());
		//更新库存
//		this.ioBillService.updateInventory(bill, entryList);
		//打印出货单及添加出货信息
		
		this.inventoryService.upDdFile(bill.getId(), orderIdSet);
		log.info("销售出库完成" + billNo);
		return result.success("销售出库完成");
	}
	
	private List<String> getParentCategory(List<String> categoryList, String categoryId) {
		BasMaterialCategory category = this.categoryService.getById(categoryId);
		String pid = category.getPid();
		if(StringUtils.isNotBlank(pid) && !StringUtils.equals("0",pid)) {
			categoryList.add(pid);
			categoryList = getParentCategory(categoryList, pid);
		}
		return categoryList;
	}
	
	@Override
	public Result<Object> findWarehouse(String userId, Result<Object> result) {
		if(StringUtils.isBlank(userId)) {
			return result.error500("用户不存在");
		}
		QueryWrapper<BasWarehouse> wrapper = new QueryWrapper<BasWarehouse>();
		wrapper.eq("is_enabled", 1);
		wrapper.ne("id", "1310776802430914562");
		wrapper.ne("id", "1315841495892500482");
		List<BasWarehouse> list = warehouseService.list(wrapper);
		result.setResult(list);
		result.setSuccess(true);
		result.setCode(CommonConstant.SC_OK_200);
		
		return result;
	}

	/**
	 * @Description: 盘点
	 * @param inventory
	 * @param result
	 * @return
	 * Create at: 2020-08-27 09:55:38
	 * @author: duanyong
	 * Revision:
	 *    2020-08-27 09:55:38 - first revision by duanyong
	 *        
	 */
	@Override
	public Result<Object> inventory(ScanInventory inventory, Result<Object> result) {
		log.info("盘点" + inventory.getWarehouseId() + inventory.getList());
		JSONArray jList = JSON.parseArray(inventory.getList());
		List<InventoryVo> list = Lists.newArrayList();
		for (int i = 0; i < jList.size(); i++) {
			JSONObject jsonObject = jList.getJSONObject(i);
			InventoryVo vo = new InventoryVo();
			vo.setCode(jsonObject.getString("code"));
			list.add(vo);
		}
		if (null == list || 0 == list.size()) {
			return result.error500("请扫描物料编码。");
		}
		String marehouseId = inventory.getWarehouseId();
		if (StringUtils.isBlank(marehouseId)) {
			return result.error500("请选择仓库");
		}
		String userId = inventory.getUserId();
		String userName = inventory.getUserName();
		if (StringUtils.isBlank(userId) || StringUtils.isBlank(userName)) {
			return result.error500("未找到登录用户");
		}
		List<String> codeList = new LinkedList<>();
		for (InventoryVo iv : list) {
			codeList.add(iv.getCode());
		}
		
		Map<String, BasMaterial> materialMap = new LinkedHashMap<>();
		Map<String, BasMaterial> materialIdMap = new LinkedHashMap<>();
		List<BasMaterial> materialList = materialService.list(new QueryWrapper<BasMaterial>().in("code", codeList));
		if(null == materialList || 0 == materialList.size()) {
			return result.error500("未发现扫描的物料。");
		}
		//封装物料信息，方便程序调用
		List<String> materialIdList = new ArrayList<>();
		for (BasMaterial basMaterial : materialList) {
			materialMap.put(basMaterial.getCode(), basMaterial);
			materialIdMap.put(basMaterial.getId(), basMaterial);
			materialIdList.add(basMaterial.getId());
		}
		//查询出入库单明细
		QueryWrapper<StkIoBillEntry> billEntryWrapper = new QueryWrapper<>();
		billEntryWrapper.eq("warehouse_id", marehouseId);
		List<StkIoBillEntry> billEntrys = this.billEntryService.list(billEntryWrapper);
		if (null == billEntrys || 0 == billEntrys.size()) {
			return result.error500("未发现扫描物料的出入库明细");
		}
		//根据入库单明细查询入库单
		Map<String, StkIoBillEntry> ioBillIds = new LinkedHashMap<>();
		for (StkIoBillEntry en : billEntrys) {
			ioBillIds.put(en.getMid(), en);
		}
		
		QueryWrapper<StkIoBill> billWrapper = new QueryWrapper<>();
		billWrapper.in("id", ioBillIds.keySet());
		List<StkIoBill> bills = this.ioBillService.list(billWrapper);
		Map<String, StkIoBill> ioBillMap = new LinkedHashMap<>();
		for (StkIoBill stkIoBill : bills) {
			ioBillMap.put(stkIoBill.getId(), stkIoBill);
		}
		
		log.info("开始封装盘点卡信息");
		//封装盘点信息
		Timestamp time = DateUtils.gettimestamp();
		StkCheckBill checkBill = new StkCheckBill();
		String billNo = baseApi.getNoByCode("stock_check_bill_no");
		checkBill.setBillNo(billNo);
		checkBill.setBillDate(time);
		checkBill.setWarehouseId(marehouseId);
		checkBill.setCheckerId(userName);
		checkBill.setApproverId(userName);
		checkBill.setBillProcStatus("12");
		checkBill.setIsApproved(0);
		checkBill.setIsVoided(0);
		checkBill.setIsClosed(0);
		checkBill.setSysOrgCode(inventory.getOrgCode());
		checkBill.setCreateBy(userName);
		checkBill.setCreateTime(time);
		
		List<StkCheckBillEntry> entrys = new LinkedList<>();
		int entryNo = 1;
		for(BasMaterial material : materialList) {
			StkCheckBillEntry entry = new StkCheckBillEntry();
			entry.setBillNo(billNo);
			entry.setMid(checkBill.getId());
			entry.setEntryNo(new Integer(entryNo));
			entry.setWarehouseId(marehouseId);
			entry.setSupplierId(material.getSupplier());
			entry.setUnitId(material.getUnitId());
			entry.setBatchNo(billNo + "-" + (entryNo*10));
			entry.setMaterialId(material.getId());
			entry.setIsNewBatch(1);
			BigDecimal decimal = this.getMaterialNumber(material.getId(), billEntrys, ioBillMap);
			entry.setBookQty(decimal);
			entry.setQty(decimal);
			entrys.add(entry);
			
			entryNo++;
		}
		this.checkBillService.saveMain(checkBill, entrys);
		log.info("盘点卡信息保存完成");
		//更新实时库存
		for (StkCheckBillEntry stkCheckBillEntry : entrys) {
			QueryWrapper<StkInventory>  inventoryWrapper = new QueryWrapper<>();
			inventoryWrapper.eq("material_id", stkCheckBillEntry.getMaterialId());
			inventoryWrapper.eq("warehouse_id", marehouseId);
			List<StkInventory> invenList = this.inventoryService.list(inventoryWrapper);
			if (null == invenList || 0 == invenList.size()) {
				StkInventory inven = new StkInventory();
				inven.setCreateTime(time);
				
				//TODO
				inven.setCost(BigDecimal.ZERO);
				inven.setIsSingleSupplier(1);
				inven.setSupplierId(stkCheckBillEntry.getSupplierId());
				inven.setCreateBy(userName);
				inven.setIsClosed(0);
				inven.setUnitId(stkCheckBillEntry.getUnitId());
				inven.setMaterialId(stkCheckBillEntry.getMaterialId());
				inven.setWarehouseId(marehouseId);
				inven.setSysOrgCode(inventory.getOrgCode());
				inven.setQty(stkCheckBillEntry.getQty());
				String batchNo = baseApi.getNoByCode("real_time_inventory_no");
				inven.setBatchNo(batchNo);
				if (stkCheckBillEntry.getQty().compareTo(BigDecimal.ZERO) > 0) {
					this.inventoryService.save(inven);
					log.info("实时库存新增完成。金额为：" + stkCheckBillEntry.getQty());
				}
			} else {
				StkInventory inven = invenList.get(0);
				inven.setQty(stkCheckBillEntry.getQty());
				this.inventoryService.updateById(inven);
				log.info("实时库存更新完成。金额为：" + stkCheckBillEntry.getQty());
			}
		}
		log.info("实时库存更新完成");
		//更新商城库存
		this.inventoryService.changeStoreInventory(materialIdList);
		
		return result.success("盘点完成");
	}

	/**
	 * @Description: 查询客户
	 * @param userId
	 * @param result
	 * @return
	 * Create at: 2020-08-22 16:25:40
	 * @author: duanyong
	 * Revision:
	 *    2020-08-22 16:25:40 - first revision by duanyong
	 *        
	 */
	@Override
	public Result<Object> findCustomer(String userId, Result<Object> result) {
		// TODO Auto-generated method stub
		QueryWrapper<BasCustomer> queryWrapper = new QueryWrapper<BasCustomer>();
		queryWrapper.eq("is_enabled", 1);
		queryWrapper.orderByAsc("name");
		List<BasCustomer> list = customerService.list(queryWrapper);
		list = ScanUtil.changeListToVector(list);
		result.setSuccess(true);
		result.setCode(200);
		result.setResult(list);
		return result;
	}
	
	/**
	 * @Description 查询并获取物料数量
	 * @param materialId
	 * @param entrys
	 * @param ioBillMap
	 * @return
	 * Create at: 2020-08-24 15:14:57
	 * @author: duanyong
	 * Revision:
	 *    2020-08-24 15:14:57 - first revision by duanyong
	 *        
	 */
	private BigDecimal getMaterialNumber(String materialId, List<StkIoBillEntry> entrys, Map<String, StkIoBill> ioBillMap) {
		BigDecimal result = BigDecimal.ZERO;
		for (StkIoBillEntry entry : entrys) {
			if(!entry.getMaterialId().equals(materialId)) {
				try {
					
				} catch (Exception e) {
					e.printStackTrace();
				}
				continue;
			}
			StkIoBill bill = ioBillMap.get(entry.getMid());
			if (null == bill) {
				continue;
			}
			if (bill.getIsClosed() != null && bill.getIsClosed() == 1) {
				continue;
			}
			String status = bill.getBillProcStatus();
			if (StringUtils.isBlank(status.trim())) {
				continue;
			}
			int statusNum = getStatusNum(status.trim());
			if (statusNum < 23) {
				continue;
			}
			String type = bill.getStockIoType();
			if (inTypes.contains(type)) {
				result = result.add(entry.getQty());
			} else if (outTypes.contains(type)) {
				result = result.subtract(entry.getQty());
			}
		}
		return result;
	}
	
	private int getStatusNum(String status) {
		DecimalFormat format = new DecimalFormat("0.000000");
        String endZeroStr = format.format(Integer.parseInt(status));
        return Integer.parseInt(endZeroStr.replace(".","").substring(0,2));
	}

	@Override
	public Result<Object> getMaterial(String userId, Result<Object> result) {
		LambdaQueryWrapper<BasMaterialCategory> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(BasMaterialCategory::getIsEnabled, 1);
		wrapper.ne(BasMaterialCategory::getHasChild, 1).or().isNull(BasMaterialCategory::getHasChild);
		wrapper.orderByAsc(BasMaterialCategory::getName);
		List<BasMaterialCategory> list = this.categoryService.list(wrapper);
		List<String> suppIds = Lists.newArrayList();
		for (BasMaterialCategory basMaterialCategory : list) {
			String supplierId = basMaterialCategory.getSupplierId();
			if(null != supplierId) {
				suppIds.add(supplierId);
			}
		}
		if(!suppIds.isEmpty()) {
			Map<String, BasSupplier> map = Maps.newHashMap();
			List<BasSupplier> suppliers = supplierService.lambdaQuery().in(BasSupplier::getId, suppIds).list();
			if(CollUtil.isNotEmpty(suppliers)) {
				for (BasSupplier supplier : suppliers) {
					map.put(supplier.getId(), supplier);
				}
			}
			for (BasMaterialCategory basMaterialCategory : list) {
				String supplierId = basMaterialCategory.getSupplierId();
				if(null != supplierId) {
					BasSupplier supplier = map.get(supplierId);
					if(null != supplier && StringUtils.isNotBlank(supplier.getShortName())) {
						String name = new StringBuffer(basMaterialCategory.getName()).append("(").append(supplier.getShortName()).append(")").toString();
						basMaterialCategory.setName(name);
					}
				}
			}
		}
		list = ScanUtil.changeListToVector(list);
		Result<Object> result2 = this.getResult(result, list, "查询物料分类失败");
//		System.out.println(JSONObject.toJSONString(result2));
		return result2;
	}

	@Override
	public Result<Object> getUnit(String userId, Result<Object> result) {
		// TODO Auto-generated method stub
		LambdaQueryWrapper<BasMeasureUnit> query = new LambdaQueryWrapper<>();
		query.eq(BasMeasureUnit::getIsEnabled, Integer.valueOf(1));
		List<BasMeasureUnit> list = this.unitService.list(query);
		return this.getResult(result, list, "查询物料单位失败");
	}

	@Override
	public Result<Object> getSupplier(String userId, Result<Object> result) {
		LambdaQueryWrapper<BasSupplier> query = new LambdaQueryWrapper<>();
		query.eq(BasSupplier::getIsEnabled, 1);
		List<BasSupplier> list = this.supplierService.list(query);
		return this.getResult(result, list, "查询供应商失败");
	}
	
	private <T> Result<Object> getResult(Result<Object> result, List<T> list, String errorStr){
		if (null != list && 0 != list.size()) {
			result.setResult(list);
			result.setSuccess(Boolean.TRUE);
			result.setCode(200);
			return result;
		}
		return result.error500(errorStr);
	}

	@Override
	public Result<?> getProcedure(String orderId) {
		List<ZrkOrderProcess> processes = processService.getProcessByOrderId(orderId);
		return Result.ok(processes);
	}
	
	public BasMaterial getMaterialByCode(String code) {
		BasMaterial material = null;
		material = this.materialService.getMaterialByCode(code);
		if(null == material) {
			material = this.materialTempService.tempToMaterial(code);
		}
		
		return material;
	}

	@Override
	public Result<?> materialCheck(ScanIO scanIo) {
		Result<Object> result = new Result<>();
		//取出存在list中的物料编码，并进行查询
		String list = scanIo.getList();
		List<String> codes = Lists.newArrayList();
		JSONArray array = JSONArray.parseArray(list);
		for (int i = 0; i < array.size(); i++) {
			JSONObject object = array.getJSONObject(i);
			codes.add(object.getString("code"));
		}
		//通过工序查询该MES单的提货单，并检查出货物料是否根提货单相同。
		String mesId = scanIo.getOrderNum();
		List<StkPickUpBill> bills = pickUpBillService.getByMesId(mesId);
		if(CollUtil.isEmpty(bills)) {
			return result.error500("未找到相关MES单的提货单。");
		}
		StkPickUpBill bill = bills.get(0);
		List<StkPickUpEntry> pickUpEntryList = pickUpEntryService.selectByMainId(bill.getId());
		if(null == pickUpEntryList || 0 == pickUpEntryList.size()) {
			return result.error500("未找到相关MES单的提货详情。");
		}
		Map<String, StkPickUpEntry> entryMap = Maps.newHashMap();
		for (StkPickUpEntry stkPickUpEntry : pickUpEntryList) {
			entryMap.put(stkPickUpEntry.getMaterialCode(), stkPickUpEntry);
		}
		//取出扫码的物料
		List<BasMaterial> materials = this.materialService.getByCodes(codes);
		if(materials == null || materials.size() == 0) {
			return result.error500("根据扫描的编码查不到相关的物料。");
		}
		//判断要扫码出库的物料是不是跟提货单中的物料符合。
		for (BasMaterial check : materials) {
			boolean flag = false;
			boolean materFlag = false;
			for (StkPickUpEntry stkPickUpEntry : pickUpEntryList) {
				String materialId = stkPickUpEntry.getMaterialId();
				if(StringUtils.isNotBlank(materialId) && materialId.equals(check.getId())) {
					materFlag = true;
					break;
				}
				String categoryId = stkPickUpEntry.getCategoryId();
				List<BasMaterialCategory> childrenList = categoryMapper.getAllChildCategoryHasChild(categoryId);
				if(CollUtil.isNotEmpty(childrenList)){
					List<String> cateIds = Lists.newArrayList();
					for(BasMaterialCategory basMaterialCategory : childrenList){
						cateIds.add(basMaterialCategory.getId());
					}
					if(cateIds.contains(check.getCategoryId())) {
						flag = true;
					}
				}
				if(StringUtils.isNotBlank(categoryId) && categoryId.equals(check.getCategoryId())) {
					flag = true;
				}
			}
			if(!flag && !materFlag) {
				return result.error500("扫瞄的物料与提货单中的物料不符。");
			}
			
		}
		//查询生产订单
		String orderId = scanIo.getOrderNum();
		ZrkQzOrder mes = this.mesService.getById(orderId);
		if(null == mes) {
			return result.error500("未找到相关的生产订单");
		}
		//取出物料最近的出入库情况
		for (BasMaterial material : materials) {
			List<StkIoBill> ioBillList = this.billMapper.getIoBillByMaterial(material.getId());
			if(null == ioBillList || 0 == ioBillList.size()) {
				return result.error500("物料并未入库");
			}
			//取出最近的一条单据
			StkIoBill bill1 = ioBillList.get(0);
			String billType = bill1.getStockIoType();
//			String billStatus = bill1.getBillProcStatus();
//			Integer integer = Integer.parseInt(StringUtils.rightPad(billStatus, 3, "0"));
			if(outTypes.contains(billType)) {
				return result.error500("物料已经出库了");
			}
			//获取物料之前的入库信息
			LambdaQueryWrapper<StkIoBillEntry> entryQuery = new LambdaQueryWrapper<>();
			entryQuery.eq(StkIoBillEntry::getMid, bill1.getId());
			entryQuery.eq(StkIoBillEntry::getMaterialId, material.getId());
			List<StkIoBillEntry> inEntrys = this.billEntryService.list(entryQuery);
			StkIoBillEntry inEntry = inEntrys.get(0);
			//判断库存中的物料
			BigDecimal checkNumber = inEntry.getQty();
			if (null == checkNumber || checkNumber.compareTo(BigDecimal.ZERO) <= 0) {
				return result.error500("物料库存不足");
			}
			String warehouseId = inEntry.getWarehouseId();
			if("301".equals(billType)) {
				warehouseId = inEntry.getInWarehouseId();
			}
			boolean warehouseResult = this.warehouseService.checkWarehouseProduce(warehouseId);
			if(!warehouseResult) {
				return result.error500("物料所在仓库不在半成品库或原料库，不能用于生产");
			}
			//判断物料和输入的仓库是否匹配
//			StkInventory inventory = this.inventoryService.selectByWarehouseAndMaterial(scanIo.getWarehouseId(), material.getId());
//			if(null == inventory) {
//				return result.error500("物料与仓库不符，请检查");
//			}
		}
		String type = scanIo.getOperType();
		//如果是复合工序进行的出库
		if("2991".equals(type)) {
			//根据产品配方验证出库产品是否正确
			String formulaId = mes.getFormulaId();
			BasProductFormula formula = formulaService.getById(formulaId);
			List<BasPfMaterial> pfList = pfMaterialService.selectByMainId(formulaId);
			if(CollUtil.isNotEmpty(pfList)) {
				//查询产品的相关配方
				List<String> categoryIds = CollUtil.newArrayList();
				for (BasPfMaterial pf : pfList) {
					String categoryId = pf.getPfName();
					categoryIds.add(categoryId);
				}
				//检查出库物料是否符合配方
				boolean flag = false;
				for(BasMaterial basMaterial : materials) {
					if(!categoryIds.contains(basMaterial.getCategoryId())) {
						flag = true;
					}
				}
				if(flag) {
					return result.error500("出库物料与配方不符。");
				}
			}
		}
		//如果是分切和切张工序进行的出库
		if(ImmutableList.of("2992").contains(type)) {
//			String processId = scanIo.getProcedureId();
//			ZrkOrderProcess orderProcess = this.processService.getById(processId);
//			if(!orderProcess.getFqCategory().equals(material.getId())) {
//				return result.error500("出库物料与工序对应的物料不符");
//			}
		}
		//如果是切张工序进行的出库
		if("2993".equals(type)) {
			
		}
		
		return result;
	}

	@Override
	@Transactional
	public Result<?> tray(ScanIO scanIo) {
		Integer printNum = scanIo.getBatchNum();
		if(null == printNum) {
			return Result.error("请输入打印数量");
		}
		if(printNum.intValue() <= 0) {
			return Result.error("请填写正确的打印数量");
		}
		String customerId = scanIo.getCustomerId();
		if(StringUtils.isBlank(customerId)) {
			return Result.error("请选择客户");
		}
		
		Date date = DateUtils.getTimestamp();
		List<String> codes = CollUtil.newArrayList();
		for(int i = 0; i < printNum; i++) {
			String code = trayService.createTrayCode();
			StkTray tray = new StkTray();
			tray.setCreateTime(date);
			tray.setCode(code);
			tray.setCustomerId(customerId);
			tray.setIsUse(0);
			boolean saveFlag = this.trayService.save(tray);
			if(saveFlag) {
				codes.add(code);
			}
		}
		
		return Result.ok(codes);
	}

	@Override
	public Result<?> shipment(ScanIO scanIo) {
		String userId = scanIo.getUserId();
		String userName = scanIo.getUserName();
		if(StringUtils.isBlank(userId) || StringUtils.isBlank(userName)) {
			return Result.error("请重新登陆");
		}
		//对传入的参数进行验证
		String listStr = scanIo.getList();
		if(StringUtils.isBlank(listStr)) {
			return Result.error("请扫码");
		}
		JSONArray jList = JSON.parseArray(listStr);
		if(null == jList || 0 == jList.size()) {
			return Result.error("请扫码");
		}
		String orderNum = scanIo.getOrderNum();
		if(StringUtils.isBlank(orderNum)) {
			return Result.error("没有扫描到出库单信息");
		}
		StkIoBill shipmentIoBill = this.billService.getByCode(orderNum);
		if(null == shipmentIoBill) {
			return Result.error("未检测到后台有该销售出库单，请核对销售出库单是否正确");
		}
		if(!"201".equals(shipmentIoBill.getStockIoType())) {
			return Result.error("不是销售出库单");
		}
		//""
		Date date = DateUtils.gettimestamp();
		//获得所有的托盘
		List<String> trayCodes = Lists.newArrayList();
		for (int i = 0; i < jList.size(); i++) {
			JSONObject object = jList.getJSONObject(i);
			String code = object.getString("code");
			trayCodes.add(code);
		}
		List<StkTray> trayList = this.trayService.getTrayByCodes(trayCodes);
		if(trayList == null || trayList.size() == 0) {
			return Result.error("未找到托盘");
		}
		//检查托盘与出库单是否一致
		boolean isBillTrayFlag = false;
		List<String> trayIds = Lists.newArrayList();
		List<StkTray> updateTrayList = Lists.newArrayList();
		for (StkTray stkTray : trayList) {
			String billId = stkTray.getBillId();
			if(StringUtils.isNotBlank(billId) && !billId.equals(shipmentIoBill.getId())) {
				isBillTrayFlag = true;
				break;
			}
			trayIds.add(stkTray.getId());
			updateTrayList.add(stkTray);
		}
		String stkTrayId = StringUtils.join(trayIds, ",");//拼接托盘ID
		if(isBillTrayFlag) {
			return Result.error("出货的托盘与销售出货单不符，请核对");
		}
		//检查托盘中的物料是否与出库单中明细一致
		List<StkIoBillEntry> entrys = this.billEntryService.selectByMainId(shipmentIoBill.getId());
		if(entrys == null || 0 == entrys.size()) {
			return Result.error("出库单数据异常，请检查");
		}
		Map<String, StkIoBillEntry> entryMap = Maps.newHashMap();
		for (StkIoBillEntry entry : entrys) {
			entryMap.put(entry.getMaterialId(), entry);
		}
		List<String> materialIds = Lists.newArrayList();
		for (StkTray stkTray : trayList) {
			List<StkTrayDetail> details = this.trayDetailService.selectByMainId(stkTray.getId());
			if(details == null || details.size() == 0) {
				return Result.error("托盘" + stkTray.getCode() + "为空，请检查");
			}
			for (StkTrayDetail detail : details) {
				materialIds.add(detail.getMaterialId());
			}
		}
		for (String string : materialIds) {
			if(null == entryMap.get(string)) {
				return Result.error("托盘中有物料与出库单不符，请检查");
			}
		}
		ZrkDeliver deliver = new ZrkDeliver();
		String code = baseApi.getNoByCode("sale_shipment_bill_no");
		deliver.setDeliverCode(code);
		deliver.setCreateBy(userName);
		deliver.setBillNo(shipmentIoBill.getBillNo());
		deliver.setCreateTime(date);
		deliver.setStkTrayId(stkTrayId);
		List<ZrkDeliverEntry> entryList = Lists.newArrayList();
		List<BasMaterial> materials = materialService.getByIds(materialIds);
		for (BasMaterial material : materials) {
			ZrkDeliverEntry entry = new ZrkDeliverEntry();
			entryList.add(entry);
			entry.setCreateBy(userName);
			entry.setCreateTime(date);
			entry.setMaterialId(material.getId());
			entry.setSquare(material.getSquare());
			StkIoBillEntry billEntry = entryMap.get(material.getId());
			entry.setMaterialCount(billEntry.getQty());
			entry.setUnitId(billEntry.getUnitId());
		}
		this.deliverService.saveMain(deliver, entryList);
		for (StkTray stkTray : updateTrayList) {
			stkTray.setDeliverCode(code);
			stkTray.setDeliverId(deliver.getId());
		}
		trayService.updateBatchById(updateTrayList);
		return Result.ok(ImmutableMap.of("code", code));
	}

	@Override
	public Result<?> getSaleOutBill(String materialCode) {
		StkIoBill bill = this.billService.getSaleOutBill(materialCode);
		if(null == bill) {
			return Result.error("没有查询到该商品的出库记录。");
		}
		String billNo = bill.getBillNo();
		String billId = bill.getId();
		Map<String, String> map = ImmutableMap.of("billNo", billNo, "order", billId);
		return Result.ok(map);
	}
}
